我正在尝试使用CloseHandle释放USB接口的句柄。我得到的例外是:
System.Runtime.InteropServices.SEHException(0x80004005):外部 组件引发了异常。在 Device.Net.APICalls.CloseHandle(SafeFileHandle hObject)位于 Usb.Net.Windows.UsbInterface.Dispose()在 C:\ GitRepos \ Device.Net \ src \ Usb.Net \ Windows \ UsbInterface.cs:第23行
在Usb.Net.Windows.WindowsUsbDevice.Dispose()中 C:\ GitRepos \ Device.Net \ src \ Usb.Net \ Windows \ WindowsUsbDevice.cs:line 131
我正在尝试在班级的Dispose方法中执行此操作。
编辑背景: 我尝试执行此操作的原因是,我的代码第二次运行时崩溃。根据此article,我必须在用CreateFile创建的设备的句柄上调用CloseHandle。无论如何,这是在我的代码中完成的,因为设备的句柄因为是SafeFileHandle而被处置。但是,有人告诉我,我需要在该接口的句柄上调用CloseHandle。我不知道这是不是真的。我正在尝试执行此操作,以排除不调用CloseHandle是该错误的原因的可能性。根据其他评论和研究,我现在认为这是一个错误,调用WinUsb_Free应该足够了。这是正确的吗?
Hans Passant在下面的回答是告诉我删除对CloseHandle的调用,但是正如我在注释中所指出的那样,原始代码(在master中)从来没有首先调用CloseHandle。当然,删除呼叫会起作用,但这不是问题。下面的问题是:使用WinUSB API释放USB接口的过程是什么?。仅仅是调用WinUsb_Free吗?那就是我所拥有的所有信息使我相信。
这是我问这个问题之前的原始处理方法。它没有对CloseHandle的调用。
public void Dispose()
{
if (_IsDisposed) return;
_IsDisposed = true;
var isSuccess = WinUsbApiCalls.WinUsb_Free(Handle);
WindowsDeviceBase.HandleError(isSuccess, "Interface could not be disposed");
}
从WindowsUsbInterface(https://github.com/MelbourneDeveloper/Device.Net/blob/9ebc122a2755dda2824c6eda961d092f2f6e83b5/src/Usb.Net/Windows/WindowsUsbDevice.cs#L122):
public override void Dispose()
{
if (_IsDisposing) return;
_IsDisposing = true;
try
{
foreach (var usbInterface in _UsbInterfaces)
{
usbInterface.Dispose();
}
_UsbInterfaces.Clear();
_DeviceHandle?.Dispose();
_DeviceHandle = null;
base.Dispose();
}
catch (Exception ex)
{
Logger.Log("Error disposing of device", ex, nameof(WindowsUsbDevice));
}
_IsDisposing = false;
}
从UsbInterface(https://github.com/MelbourneDeveloper/Device.Net/blob/9ebc122a2755dda2824c6eda961d092f2f6e83b5/src/Usb.Net/Windows/UsbInterface.cs#L18):
public void Dispose()
{
var isSuccess = WinUsbApiCalls.WinUsb_Free(Handle);
WindowsDeviceBase.HandleError(isSuccess, "Interface could not be disposed");
isSuccess = APICalls.CloseHandle(Handle);
WindowsDeviceBase.HandleError(isSuccess, "Interface could not be disposed");
}
API调用定义(https://github.com/MelbourneDeveloper/Device.Net/blob/CloseHandle/src/Device.Net/Windows/APICalls.cs):
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(SafeFileHandle hObject);
我也尝试过简单地处理该句柄,因为它是一个SafeFileHandle,但是SafeFileHandle的Dispose方法会给我同样的错误消息。这向我暗示了SafeFileHandle的Dispose方法可能也正在调用CloseHandle,并且发生了相同的问题。
其他人提到我应该使用IntPtr而不是SafeFileHandle。因此,我尝试在CloseHandle的接口上使用IntPtr,但问题是相同的:
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out IntPtr InterfaceHandle);
使用WinUSB API释放USB接口的过程是什么?在C#中我需要做些不同的事情吗?为什么会出现此错误?
答案 0 :(得分:10)
CloseHandle()失败。深入研究github源代码,我发现了问题的出处:
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle,
out SafeFileHandle InterfaceHandle);
经过编辑以适合并使问题更明显。第二个参数的类型不正确,该函数未返回kernel32句柄,因此将其包装在SafeFileHandle中是不正确的。这是一个不透明的句柄,在本机api声明中为WINUSB_INTERFACE_HANDLE,通常是一个隐藏的指针。关闭它只有一种正确的方法,您必须调用WinUsb_Free()。代码可以这样做,但是也调用CloseHandle是不正确的,并且注定会失败。 SafeFileHandle提供的CloseHandle()调用同样会失败,您可能还没走那么远。
将参数类型更改为IntPtr
。这需要其他几处代码更改,主要是在UsbInterface类中。同样,将其Handle属性类型更改为IntPtr。在其Dispose()方法中删除CloseHandle()调用。编写自己的SafeHandle派生类来包装它是另一种方法,然后重写ReleaseHandle()来调用WinUsb_Free()。
答案 1 :(得分:-1)
我认为这个问题的答案是没有必要在USB接口上调用CloseHandle。按照本页顶部的Dispose方法,调用WinUsb_Free应该足以释放接口。只需调用CloseHandle即可释放由CreateFile创建的设备的句柄。
public void Dispose()
{
if (_IsDisposed) return;
_IsDisposed = true;
var isSuccess = WinUsbApiCalls.WinUsb_Free(Handle);
WindowsDeviceBase.HandleError(isSuccess, "Interface could not be disposed");
}
这个article非常清楚。
- CloseHandle释放由CreateFile创建的句柄,如步骤1所述。
- WinUsb_Free释放设备的WinUSB接口句柄,由WinUsb_Initialize返回。
汉斯·帕桑特还建议:
在其Dispose()方法中删除CloseHandle()调用
也来自Hans Passant:
第二个参数的类型不正确,该函数不正确 返回kernel32句柄,因此不将其包装在SafeFileHandle中 正确。这是一个不透明的句柄,它位于WINUSB_INTERFACE_HANDLE 本地api声明,通常是一个隐藏的指针。有 只有一种正确的关闭方式,您必须调用WinUsb_Free()。
这并不能直接解决我所问的问题,但这是很公平的。汉斯指出,我无法在WinUsb_Initialize返回的句柄上调用Dispose()的原因是,这样做会在幕后调用CloseHandle,而WinUsb_Initialize返回的第二个参数不是kernel32句柄,因此CloseHandle()会赢得胜利。无论如何都不能工作。这只会导致这样的观点:似乎没有任何迹象表明必须在接口上调用CloseHandle。因此,我相信我遇到的问题(单独的问题)与不调用CloseHandle无关。固件本身似乎有问题,制造商似乎已确认这一点。还有更多细节。
注意:如果我错了,请告诉我为什么我错了,并举一个使用CloseHandle关闭USB接口上的句柄的示例。 < / strong>