我想知道是否有人可能对我在重叠模式下使用 kernel32.dll ReadFile 函数从串行 COM 端口异步读取 VBA 时遇到的问题有所了解?
基本上,一切正常,除了只有一个 COM 端口,传递给 ReadFile 的数据缓冲区永远不会被数据填充,但 GetOverlappedResults 确实表明已读取正确数量的字符并且异步(重叠)操作已成功完成。
奇怪的是它与 COM 端口同步工作,它与文件异步工作(而不是 COM 端口),如果在调用 ReadFile 之前 COM 端口数据可用(在这种情况下它同步完成),它会异步工作。
为了测试我没有误解它应该如何工作,我用古老的 C 语言编写了相同的代码,它运行良好。数据缓冲区按预期填充,而在 VBA 代码中,数据缓冲区没有按应有的方式填充接收到的数据。
很多天以来,我以多种方式研究了这个问题,但不知道下一步该做什么才能取得进展。
这是我简单的 VBA 代码,提炼为演示问题的基础知识:
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
感觉就像 VBA 将缓冲区视为非易失性,因此 VBA 不知道缓冲区可以自发更改。
如果有人想看,我可以发布类似的 C 代码。
谢谢你的帮助。
D