为了账号安全,请及时绑定邮箱和手机立即绑定

C# WinUSB 无法在接口上调用 CloseHandle

C# WinUSB 无法在接口上调用 CloseHandle

C#
扬帆大鱼 2022-07-23 09:16:14
我正在尝试使用 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:131 行我正在尝试在我班级的 Dispose 方法中执行此操作。编辑背景:我试图这样做的原因是我的代码在我第二次运行它时崩溃了。根据这篇文章,我必须在我用 CreateFile 创建的设备的句柄上调用 CloseHandle。无论如何,这是在我的代码中完成的,因为设备的句柄正在被释放,因为它是一个 SafeFileHandle。但是,有人告诉我,我需要在接口的句柄上调用 CloseHandle。我不知道这是否属实。我试图这样做以排除不调用 CloseHandle 是导致该错误的原因的可能性。根据其他评论和研究,我现在认为这是一个错误,调用 WinUsb_Free 就足够了。这个对吗?Hans Passant 在下面的回答是告诉我删除对 CloseHandle 的调用,但正如我在评论中指出的那样,原始代码(在 master 中)从一开始就从未调用过 CloseHandle。当然,删除呼叫会起作用,但这不是问题。下面的问题是:用WinUSB API发布USB接口的流程是什么?. 仅仅是调用 WinUsb_Free 吗?这就是我所掌握的所有信息让我相信的。这是我问这个问题之前的原始处置方法。它没有对 CloseHandle 的调用。来自 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,并且正在发生同样的问题。
查看完整描述

2 回答

?
largeQ

TA贡献2039条经验 获得超8个赞

当句柄不是正确的 kernel32 句柄或句柄已关闭时,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()。


查看完整回答
反对 回复 2022-07-23
?
月关宝盒

TA贡献1772条经验 获得超5个赞

我认为这个问题的答案是没有必要在 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");

}

这篇文章说得很清楚。


CloseHandle 释放由 CreateFile 创建的句柄,如步骤 1 中所述。

WinUsb_Free 释放设备的 WinUSB 接口句柄,由 WinUsb_Initialize 返回。

Hans Passant 还推荐:


在 Dispose() 方法中删除 CloseHandle() 调用


此外,来自汉斯·帕桑特:


第二个参数的类型不正确,该函数不返回 kernel32 句柄,因此将其包装在 SafeFileHandle 中是不正确的。这是一个不透明的句柄,本机 api 声明中的 WINUSB_INTERFACE_HANDLE,通常是引擎盖下的指针。只有一种正确的方法可以关闭它,您必须调用 WinUsb_Free()。


这并不直接涉及我所问的问题,但这是一个公平的观点。正如 Hans 指出的那样,我不能在 WinUsb_Initialize 返回的句柄上调用 Dispose() 的原因是这样做会在后台调用 CloseHandle,而 WinUsb_Initialize 返回的第二个参数不是 kernel32 句柄,所以 CloseHandle() 只是赢了'无论如何都行不通。这只是导致似乎没有任何迹象表明有必要在接口上调用 CloseHandle。所以,我相信我遇到的问题(单独的问题)与不调用 CloseHandle 无关。这似乎是固件本身的问题,制造商似乎已经确认了这一点。更多细节即将到来。


注意:如果我错了,请告诉我为什么我错了,并指出一个使用 CloseHandle 关闭 USB 接口上的句柄的示例。


查看完整回答
反对 回复 2022-07-23
  • 2 回答
  • 0 关注
  • 506 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号