【问题标题】:Overlapped.AsyncResult doesn't change even after operation completed successfullyOverlapped.AsyncResult 即使在操作成功完成后也不会改变
【发布时间】:2020-11-28 11:05:19
【问题描述】:

为了与 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 仍然为空,尽管写入成功完成;我确定是因为设备正确接收数据和响应。我的代码有什么问题?

【问题讨论】:

  • You can find complete code in Microchip MLA custom HID device project - 问题本身必须包含所有相关代码。
  • @GSerg “所有相关代码”将变得非常大!此外,有经验的人应该能够检测到我的错误,因为我包含了最重要的部分,而其他部分在大多数应用程序中都是相同的。
  • @GSerg 我添加了ref,但情况变得更糟:Managed Debugging Assistant 'FatalExecutionEngineError' : 'The runtime has encountered a fatal error...'
  • 你能不能不简单do this
  • Overlapped 类具有采用 IAsyncResult 参数的构造函数。旨在使异步使用实用,重叠 I/O 的意图,单个回调方法可以处理多个异步读取。您没有使用这样的构造函数,也没有做任何明显的事情来处理异步完成,因此 AsyncResult 必须为空。如果您编写等待完成的代码,则根本没有使用重叠或异步代码的意义。如果需要,使用 FileStream.BeginRead() 或 ReadAsync() 使其异步。

标签: c# kernel32 overlapped-io


【解决方案1】:

感谢 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/awaitWriteAsync

我可以使用ReadFile 而不是HID.Write,但关闭句柄会更难。此外,使用托管 C# 方法比导入和使用非托管 C++ 函数更好。

编辑: 我还为 BeginRead 添加了一个代码:

IAsyncResult result = HID.BeginRead(INBuffer, 0, 65, null, null);
while (FavoriteCondition)
{
    MethodWhichShouldBeCalledRepeatedly();
    if (result.IsCompleted)
    {
        ProcessData(INBuffer);
    }
}

【讨论】:

  • 那是你在那里做的非常错误的事情。请参阅stackoverflow.com/a/13140963/11683blog.stephencleary.com/2013/08/startnew-is-dangerous.html,并像在example 中一样简单地使用await
  • @GSerg 对不起!你说得对。我忘了提到//Some Code 部分。代码将开始写入,执行一些其他代码,然后等待写入结果。我不能使用async,因为.Net 4.0(我的应用程序的目标)中没有Stream.ReadAsync方法,并且Stream.BeginWrite不支持async
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
相关资源
最近更新 更多