【发布时间】:2013-02-08 15:27:23
【问题描述】:
我正在使用 Async 通过 c# 读取 USB 设备。我正在使用文件流来做到这一点。当我执行 FileStream.BeginRead 时。它似乎没有做回调。这是什么问题?
这是我的代码
/// <summary>
/// Initialises the device
/// </summary>
/// <param name="strPath">Path to the device</param>
private void Initialise(String strPath)
{
// Create the file from the device path
SafeHandle = CreateFile(strPath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open,
EFileAttributes.Overlapped, IntPtr.Zero);
if (SafeHandle != null) // if the open worked...
{
IntPtr lpData;
if (HidD_GetPreparsedData(SafeHandle, out lpData))
// get windows to read the device data into an internal buffer
{
try
{
HidCaps hidCaps;
HidP_GetCaps(lpData, out hidCaps); // extract the device capabilities from the internal buffer
InputReportLength = hidCaps.InputReportByteLength; // get the input...
OutputReportLength = hidCaps.OutputReportByteLength; // ... and output report lengths
FileStream = new FileStream((SafeFileHandle) SafeHandle, FileAccess.ReadWrite, InputReportLength,
true); // wrap the file handle in a .Net file stream
BeginAsyncRead(); // kick off the first asynchronous read
}
finally
{
HidD_FreePreparsedData(ref lpData);
// before we quit the function, we must free the internal buffer reserved in GetPreparsedData
}
}
else // GetPreparsedData failed? Chuck an exception
throw HidDeviceException.GenerateWithWinError("GetPreparsedData failed");
}
else // File open failed? Chuck an exception
{
SafeHandle = null;
throw HidDeviceException.GenerateWithWinError("Failed to create device file");
}
}
这是回调
/// <summary>
/// Kicks off an asynchronous read which completes when data is read or when the device
/// is disconnected. Uses a callback.
/// </summary>
private void BeginAsyncRead()
{
Byte[] buffer = new Byte[InputReportLength];
// put the buff we used to receive the stuff as the async state then we can get at it when the read completes
FileStream.BeginRead(buffer, 0, InputReportLength, ReadCompleted, buffer);
}
这是我的回调
/// <summary>
/// Callback for above. Care with this as it will be called on the background thread from the async read
/// </summary>
/// <param name="iResult">Async result parameter</param>
private void ReadCompleted(IAsyncResult iResult)
{
Byte[] buffer = (Byte[])iResult.AsyncState; // retrieve the read buffer
try
{
FileStream.EndRead(iResult); // call end read : this throws any exceptions that happened during the read
try
{
HandleDataReceived(buffer); // pass the new input report on to the higher level handler
}
finally
{
BeginAsyncRead(); // when all that is done, kick off another read for the next report
}
}
catch (IOException) // if we got an IO exception, the device was removed
{
HandleDeviceRemoved();
if (OnDeviceRemoved != null)
OnDeviceRemoved(this, new EventArgs());
Dispose();
}
}
更新我想知道我在 devicePath 中是否做错了
/// <summary>
/// Helper method to return the device path given a DeviceInterfaceData structure and an InfoSet handle.
/// Used in 'FindDevice' so check that method out to see how to get an InfoSet handle and a DeviceInterfaceData.
/// </summary>
/// <param name="hInfoSet">Handle to the InfoSet</param>
/// <param name="oInterface">DeviceInterfaceData structure</param>
/// <returns>The device path or null if there was some problem</returns>
private static string GetDevicePath(IntPtr hInfoSet, ref DeviceInterfaceData oInterface)
{
uint nRequiredSize = 0;
// Get the device interface details
if (!SetupDiGetDeviceInterfaceDetail(hInfoSet, ref oInterface, IntPtr.Zero, 0, ref nRequiredSize, IntPtr.Zero))
{
DeviceInterfaceDetailData oDetail = new DeviceInterfaceDetailData();
oDetail.Size = Marshal.SizeOf(typeof(IntPtr)) == 4 ? 8 : 5; // check if is a 64 bit
if (SetupDiGetDeviceInterfaceDetail(hInfoSet, ref oInterface, ref oDetail, nRequiredSize, ref nRequiredSize, IntPtr.Zero))
{
return oDetail.DevicePath;
}
}
return null;
}
【问题讨论】:
-
显示您的代码..然后其他人可以帮助您。
-
ReadCompleted 在哪里?这才是真正的关键功能。此外,不要将缓冲区作为最后一个参数发送,发送流是因为您需要关闭它(让文件无限期打开并不好)。真的,我们需要并排查看 BeginAsyncRead 和 ReadCompleted。
-
@DanielKelley 我只是我的代码的副本
-
到目前为止看起来不错,如果你在 BeginAsyncRead 和 ReadCompleted 中设置断点,你会同时击中它们吗?
-
@sircodesalot:它只隐藏 BeginAsyncRead 从不 ReadComplete