1 year ago
#229592
daholtz
VBA buffer not being filled with data by asynchronous (overlapped) Kernel32.dll ReadFile of COM port, but works synchronously
I'm wondering if someone might have some insight into a problem I'm having with VBA reading asynchronously from a serial COM port using the kernel32.dll ReadFile function in overlapped mode?
Basically, everything works except, only with a COM port, the data buffer passed to ReadFile never gets filled with the data but GetOverlappedResults does indicate that the correct number of characters have been read and the asynchronous (overlapped) operation has completed successfully.
The odd thing is that it works synchronously with the COM port, it works asynchronously with a file (instead of COM port), and it works asynchronously if COM port data is available before ReadFile is called (in which case it completes synchronously).
To test that I wasn't misunderstanding how it is supposed to work, I wrote the same code in good old C and it worked perfectly. The data buffer gets filled as expected whereas in the VBA code the data buffer doesn't get filled with the received data as it should.
I've looked at this problem in many ways over many days and don't know what to do next to make progress.
Here is my simple VBA code distilled to the very basics that demonstrate the problem:
Private Type OVERLAPPED
Internal As Long
InternalHigh As Long
offset As Long
OffsetHigh As Long
hEvent As Long
End Type
Declare Function CreateFileA Lib "kernel32" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As String, ByVal nNumberOfBytesToRead As Long, ByRef lpNumberOfBytesRead As Long, lpOverlapped As OVERLAPPED) As Long
Declare Function GetOverlappedResult Lib "kernel32" (ByVal hFile As Long, ByRef lpOverlapped As OVERLAPPED, lpNumberOfBytesTransferred As Long, ByVal bWait As Long) As Long
Declare Function GetTickCount Lib "kernel32" () As Long
Private Const FILE_GENERIC_READ = &H120089
Private Const FILE_SHARE_READ = &H1
Private Const OPEN_EXISTING = 3
Private Const FILE_FLAG_OVERLAPPED = &H40000000
Private Const ERROR_IO_INCOMPLETE = 996
Sub test()
Dim fp As Long
Dim l As Long
Dim buffer As String * 1000
Dim OVERLAPPED As OVERLAPPED
Dim r As Long
Dim t As Long
Dim filename As String
filename = "COM4"
' filename = "c:\users\dh\text.txt"
fp = CreateFile(filename, FILE_GENERIC_READ, FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)
t = GetTickCount
l = ReadFile(fp, buffer, 11, r, OVERLAPPED) 'read 11 characters asynchronously
Debug.Print "l=" & l & " r=" & r & " GetLastError=" & GetLastError & " t=" & (GetTickCount - t) / 1000
While Not GetOverlappedResult(fp, OVERLAPPED, r, 0&) And GetLastError = ERROR_IO_INCOMPLETE
Debug.Print "l=" & l & " r=" & r & " GetLastError=" & GetLastError & " t=" & (GetTickCount - t) / 1000
DoEvents 'do other stuff while waiting for FileRead to asyncronously complete.
Wend
Debug.Print "l=" & l & " r=" & r & " GetLastError=" & GetLastError & " t=" & (GetTickCount - t) / 1000
For t = 1 To r
Debug.Print "t:" & t & " C:" & Hex(Asc(Mid(buffer, t, 1)))
Next
CloseHandle (fp)
End Sub
It feels like VBA is treating the buffer as non-volatile so VBA doesn't know that the buffer can spontaneously change.
I can post the analogous C code if anyone wants to see it.
Thanks for your help.
D
vba
asynchronous
readfile
com-port
0 Answers
Your Answer