3

我想知道是否有人可能对我在重叠模式下使用 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

4

0 回答 0