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