Search code examples
.netvb.netfatal-erroraccess-violationkernel32

vb.net AccessViolationException and FatalExecutionEngineError


I have been working on this project for a week or so and at the beginning of the week, my ReadFile was returning an AccessViolationException - "Attempted to read or write protected memory." so I played around with it a little bit and it went away. I thought I fixed it but maybe not? Now my WriteFile is throwing a FatalExecutionEngineError, which after some reading seems like the two incidents could be related; I'm not sure though. Here are my declarations, there could be a problem with these:

    <DllImport("kernel32.dll")> Private Shared Function CloseHandle(
    ByVal hObject As Integer) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function CreateFile(
    <MarshalAs(UnmanagedType.LPStr)> ByVal lpFileName As String,
    ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer,
    ByVal lpSecurityAttributes As Integer,
    ByVal dwCreationDisposition As Integer,
    ByVal dwFlagsAndAttributes As Integer,
    ByVal hTemplateFile As Integer) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function GetCommState(
    ByVal hCommDev As Integer, ByRef lpDCB As DCB) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function GetCommTimeouts(
    ByVal hFile As Integer, ByRef lpCommTimeouts As COMMTIMEOUTS) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function GetLastError() As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function PurgeComm(
    ByVal hFile As Integer, ByVal dwFlags As Integer) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function ReadFile(
    ByVal hFile As Integer, ByVal Buffer As Byte(),
    ByVal nNumberOfBytesToRead As Integer,
    ByRef lpNumberOfBytesRead As Integer,
    ByRef lpOverlapped As Overlapped) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function SetCommTimeouts(
    ByVal hFile As Integer, ByRef lpCommTimeouts As COMMTIMEOUTS) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function SetCommState(
    ByVal hCommDev As Integer, ByRef lpDCB As DCB) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function WriteFile(
    ByVal hFile As Integer, ByVal Buffer As Byte(),
    ByVal nNumberOfBytesToWrite As Integer,
    ByRef lpNumberOfBytesWritten As Integer,
    ByRef lpOverlapped As Overlapped) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function SetCommMask(
    ByVal hFile As Integer,
    ByVal dwEvtMask As Integer) As Integer
End Function

<DllImport("kernel32.dll", SetLastError:=True)> Private Shared Function WaitCommEvent(
    ByVal hFile As Integer,
    ByRef mask As Integer,
    ByRef lpOverlap As Overlapped) As Integer
End Function

<DllImport("kernel32.dll")> Private Shared Function FormatMessage(
    ByVal dwFlags As Integer,
    ByVal lpSource As Integer,
    ByVal dwMessageId As Integer,
    ByVal dwLanguageId As Integer,
    ByVal lpBuffer As StringBuilder,
    ByVal nSize As Integer,
    ByVal Arguments As Integer) As Integer
End Function

And here is the code that was originally causing the AccessViolationException, which went away:

Private Function read() As String
    Dim sErrTxt As String
    Dim iReadChars, iRc As Integer

    If mhRS <> INVALID_HANDLE_VALUE Then
        ' Sets Comm Mask
        iRc = SetCommMask(mhRS, EventMasks.RxChar)
        If iRc <> 0 Then
            'Waits for a comm event
            iRc = WaitCommEvent(mhRS, miEvtMask, Nothing)
            If iRc <> 0 Then
                miStringSize = 0
                miString = ""
                ReDim mabtRxBuf(miBufferSize)
                ' Loop through the buffer and store it in a string while there is still chars in the buffer
                For i As Integer = 0 To 20
                    iRc = ReadFile(mhRS, mabtRxBuf, miBufferSize, iReadChars, Nothing)
                    If iRc <> 0 Then
                        ' Stores the size of the string read and forms the string
                        If iReadChars > 0 Then
                            miStringSize += iReadChars
                            miString &= defaultEncoding.GetString(mabtRxBuf)
                        End If
                    Else
                        ' Read Error 
                        sErrTxt = pErr2Text(GetLastError())
                        MsgBox("ReadFile failed " & sErrTxt)
                        Return Nothing
                    End If
                Next
                'Loop While iReadChars > 0
                ' Returns the concantenated string
                Return miString
            Else
                ' Handles WaitCommEvent error
                sErrTxt = pErr2Text(GetLastError())
                MsgBox("WaitCommEvent failed " & sErrTxt)
                Return Nothing
            End If
        Else
            ' Handles SetSommMask error
            sErrTxt = pErr2Text(GetLastError())
            MsgBox("Unable to SetCommMask " & sErrTxt)
            Return Nothing
        End If

    Else
        ' Handles port not open error
        MsgBox("Please initialize port first")
        Return Nothing
    End If
End Function

And finally, here is the code that is causing the FatalExecutionEngineError:

Private Sub write(ByVal byteBuff As Byte())
    Dim sErrTxt As String
    Dim bytesSent = 0, iRc, iWriteChars As Integer

    If mhRS <> INVALID_HANDLE_VALUE Then
        ' Writes the passed Byte() to the comm port
        iRc = WriteFile(mhRS, byteBuff, byteBuff.Length, iWriteChars, Nothing)
        If iRc = 0 Then
            ' Handles WriteFile error
            sErrTxt = pErr2Text(GetLastError())
            MsgBox("WriteFile Failed " & sErrTxt)
        End If
    Else
        ' Handles port not open error
        MsgBox("Please initialize port first")
        Exit Sub
    End If
End Sub

I'm using visual studio 2015 and .NET 4.6.1 on a windows 7 64-bit. I re-installed .net, which didn't work so then I transferred the application to another machine to see if it would work on there and it didn't. The second machine was the same as the first. I don't know where to go from here.


Solution

  • The code that ended up working out for me:

            Private receivedText As String
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        With miPort
            .PortName = "COM3"
            .BaudRate = 38400
            .Parity = Parity.None
            .StopBits = StopBits.One
            .DataBits = 8
            .DtrEnable = True
            .RtsEnable = True
            .Handshake = Handshake.None
            .Encoding = Encoding.GetEncoding(28591)
        End With
    End Sub
    
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Not miPort.IsOpen Then
            miPort.Open()
        End If
    
        If miPort.IsOpen Then
            miPort.Write(toCharacters("55FF0510030004BC0105010189D1"))
        End If
    End Sub
    
    ' Converts the passed string as hexidecimal numbers to its characters
    Private Function toCharacters(ByVal hexText As String) As String
        Dim num As String
        Dim sendText As String = ""
    
        For y As Integer = 1 To Len(hexText) Step 2
            ' Takes two of the numbers passed (1 byte in Hex)
            num = Mid(hexText, y, 2)
            ' Converts the numbers into their decimal number, then to their character and stores them in a String()
            sendText &= (ChrW(Val("&h" & num)))
        Next y
    
        Return sendText
    End Function
    
    Private Sub miPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles miPort.DataReceived
        receivedText = miPort.ReadExisting()
    End Sub