Overlapped.AsyncResult 即使在操作成功完成后也不会改变
Overlapped.AsyncResult doesn't change even after operation completed successfully
为了与 HID 设备通信,我使用了 kernel32 中的一些函数。代码是从 Microchip MLA 自定义 HID 设备项目中借用的。它使用阻塞方法。
我发现我可以使这些方法异步。这是我尝试进行异步写入的方法:
//...
internal const uint FILE_FLAG_OVERLAPPED = 0x40000000;
//...
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool ReadFile(
SafeFileHandle hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
ref uint lpNumberOfBytesRead,
Overlapped lpOverlapped); // Formerly: IntPtr lpOverlapped);
//...
WriteHandleToUSBDevice = CreateFile(DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero); // Formerly: 0 instead of FILE_FLAG_OVERLAPPED
//...
Overlapped OL = new Overlapped();
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, OL); // Formerly: IntPtr.Zero instead of OL
//Some code to run while write operation is in progress asynchronously...
while (OL.AsyncResult == null) ; // Wait until write is completed; waits forever.
您可以在 Microchip MLA 自定义 HID 设备项目中找到完整代码。
OL.AsyncResult
虽然写入成功完成,但仍然为空;我敢肯定,因为设备可以正确接收数据和响应。我的代码有什么问题?
感谢 Gserg 的评论,我找到了比使用 kernel32 C++ 样式函数更好的解决方案:
SafeFileHandle HandleToUSBDevice = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
IntPtr.Zero);
FileStream HID = new FileStream(HandleToUSBDevice, FileAccess.ReadWrite, (int)(PacketSize + 1), true);
Task WriteTask = Task.Factory.StartNew(() => HID.Write(OUTBuffer, 0, 65));
//Some Code
if (!WriteTask.Wait(2500)) throw new TimeoutException("Failed to send data within 2.5s timeout.");
如果您的 .Net 框架目标高于 4.5,您可以使用 async/await
和 WriteAsync
。
我可以使用 ReadFile
而不是 HID.Write
,但关闭句柄会更难。此外,使用托管 C# 方法优于导入和使用非托管 C++ 函数。
编辑:
我还为 BeginRead 添加了一个代码:
IAsyncResult result = HID.BeginRead(INBuffer, 0, 65, null, null);
while (FavoriteCondition)
{
MethodWhichShouldBeCalledRepeatedly();
if (result.IsCompleted)
{
ProcessData(INBuffer);
}
}
为了与 HID 设备通信,我使用了 kernel32 中的一些函数。代码是从 Microchip MLA 自定义 HID 设备项目中借用的。它使用阻塞方法。
我发现我可以使这些方法异步。这是我尝试进行异步写入的方法:
//...
internal const uint FILE_FLAG_OVERLAPPED = 0x40000000;
//...
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool ReadFile(
SafeFileHandle hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
ref uint lpNumberOfBytesRead,
Overlapped lpOverlapped); // Formerly: IntPtr lpOverlapped);
//...
WriteHandleToUSBDevice = CreateFile(DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero); // Formerly: 0 instead of FILE_FLAG_OVERLAPPED
//...
Overlapped OL = new Overlapped();
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, OL); // Formerly: IntPtr.Zero instead of OL
//Some code to run while write operation is in progress asynchronously...
while (OL.AsyncResult == null) ; // Wait until write is completed; waits forever.
您可以在 Microchip MLA 自定义 HID 设备项目中找到完整代码。
OL.AsyncResult
虽然写入成功完成,但仍然为空;我敢肯定,因为设备可以正确接收数据和响应。我的代码有什么问题?
感谢 Gserg 的评论,我找到了比使用 kernel32 C++ 样式函数更好的解决方案:
SafeFileHandle HandleToUSBDevice = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
IntPtr.Zero);
FileStream HID = new FileStream(HandleToUSBDevice, FileAccess.ReadWrite, (int)(PacketSize + 1), true);
Task WriteTask = Task.Factory.StartNew(() => HID.Write(OUTBuffer, 0, 65));
//Some Code
if (!WriteTask.Wait(2500)) throw new TimeoutException("Failed to send data within 2.5s timeout.");
如果您的 .Net 框架目标高于 4.5,您可以使用 async/await
和 WriteAsync
。
我可以使用 ReadFile
而不是 HID.Write
,但关闭句柄会更难。此外,使用托管 C# 方法优于导入和使用非托管 C++ 函数。
编辑: 我还为 BeginRead 添加了一个代码:
IAsyncResult result = HID.BeginRead(INBuffer, 0, 65, null, null);
while (FavoriteCondition)
{
MethodWhichShouldBeCalledRepeatedly();
if (result.IsCompleted)
{
ProcessData(INBuffer);
}
}