【发布时间】:2012-02-19 01:08:14
【问题描述】:
我的目标是创建一个能够与 USB HID 设备通信的应用程序。主 (UI) 线程创建适当的句柄。
this.handle =
Win32.CreateFile(
devicePath,
Win32.GENERIC_READ | Win32.GENERIC_WRITE,
0,
IntPtr.Zero,
Win32.OPEN_EXISTING,
Win32.FILE_FLAG_OVERLAPPED,
IntPtr.Zero);
在此之后,启动两个线程。首先是不断地从设备中读取数据。如果没有可用数据,则将其阻止。它使用重叠阅读。句柄可以传递给 FileStream 对象,但我必须使用 P/Invoke 调用。我的实现基于多个 HID 库。于是线程运行如下循环:
while (true)
{
var overlapped = new Win32.Overlapped();
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
overlapped.Event = this.readEvent;
var readResult =
Win32.ReadFile(
this.handle,
buffer,
(uint)this.InputReportLength,
IntPtr.Zero,
ref overlapped);
if (readResult == 0)
{
int errorCode = Marshal.GetLastWin32Error();
// Overlapped operation is running => 0x3e5
if (errorCode != 0x3e5)
{
break;
}
}
var result = Win32.WaitForSingleObject(overlapped.Event, Win32.WAIT_INFINITE);
if (result != Win32.WAIT_OBJECT_0 || this.handle == IntPtr.Zero)
{
// Handle is cleared
break;
}
uint bytesRead = 0;
Win32.GetOverlappedResult(this.handle, ref overlapped, out bytesRead, false);
if (bytesRead > 0)
{
byte[] report = new byte[this.InputReportLength];
Array.Copy(buffer, report, Math.Min(bytesRead, report.Length));
// Report data
OnDataReceived(report);
}
}
第二个线程使用并发队列中的命令,将它们编组为二进制,然后调用以下方法将数据写入设备。
IntPtr writeEvent = Win32.CreateEvent(IntPtr.Zero, false, true, Guid.NewGuid().ToString());
var overlapped = new Win32.Overlapped();
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
overlapped.Event = writeEvent;
int writeResult =
Win32.WriteFile(
this.handle, buffer,
(uint)buffer.Length,
IntPtr.Zero,
ref overlapped);
if (writeResult == 0)
{
int errorCode = Marshal.GetLastWin32Error();
// Overlapped operation is running => 0x3e5
if (errorCode != 0x3e5)
{
throw new IOException(string.Format("Cannot write device ({0})", errorCode));
}
}
var result = Win32.WaitForSingleObject(writeEvent, Win32.WAIT_INFINITE);
Win32.CloseHandle(writeEvent);
if (result != Win32.WAIT_OBJECT_0)
{
throw new IOException("Failed to write");
}
应用程序正确接收设备推送的数据。该程序运行顺利,没有任何故障。 但是如果应用程序向设备发送数据(通过将命令对象放入提到的队列中),整个应用程序会自发崩溃。崩溃以不确定的方式发生。这背后的原因是什么?我的想法是它是由并发访问引起的。但是,同时使用 FileStream 对象(通过将句柄传递给它)不会导致此类崩溃。
【问题讨论】:
-
没什么可看的,崩溃细节很重要。只是不要编写这种代码,使用 FileStream(SafeFileHandle, FileAccess, int, bool) 构造函数,这样您只需要 pinvoke CreateFile 并且可以以 .NET 方式执行其他所有操作。
-
@HansPassant 不幸的是,我无法向您提供崩溃的详细信息,因为应用程序无一例外地崩溃。我提到我必须使用 P/Invoke 实现。除非有人有办法将句柄推入 Silverlight 5 的 FileStream 对象。