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

标签 c# usb winusb safefilehandle

我正在尝试使用 CloseHandle 释放 USB 接口(interface)的句柄。我得到的异常(exception)是:

System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception. at Device.Net.APICalls.CloseHandle(SafeFileHandle hObject) at Usb.Net.Windows.UsbInterface.Dispose() in C:\GitRepos\Device.Net\src\Usb.Net\Windows\UsbInterface.cs:line 23
at Usb.Net.Windows.WindowsUsbDevice.Dispose() in C:\GitRepos\Device.Net\src\Usb.Net\Windows\WindowsUsbDevice.cs:line 131

我正在尝试在我的类的 Dispose 方法中执行此操作。

编辑背景: 我尝试这样做的原因是我的代码在我第二次运行时崩溃了。根据这个article ,我必须在我用 CreateFile 创建的设备的句柄上调用 CloseHandle。无论如何,这是在我的代码中完成的,因为设备的句柄正在被处理,因为它是一个 SafeFileHandle。但是,有人告诉我,我需要在接口(interface)的句柄上调用 CloseHandle。我不知道这是不是真的。我试图这样做是为了排除不调用 CloseHandle 是错误原因的可能性。根据其他评论和研究,我现在认为这是一个错误,调用 WinUsb_Free 应该就足够了。这是正确的吗?

下面 Hans Passant 的回答告诉我删除对 CloseHandle 的调用,但正如我在评论中指出的那样,原始代码(在 master 中)从来没有首先调用 CloseHandle。当然,删除调用会起作用,但这不是问题所在。下面的问题是:使用 WinUSB API 释放 USB 接口(interface)的过程是什么?。是简单调用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 的接口(interface)上使用 IntPtr,但问题是一样的: enter image description here

这里是 WinUsb_Initialize 的定义

[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out IntPtr InterfaceHandle);

使用 WinUSB API 发布 USB 接口(interface)的过程是怎样的?我需要在 C# 中做些不同的事情吗?为什么会出现这个错误?

最佳答案

当句柄不是正确的 kernel32 句柄或句柄已经关闭时,CloseHandle() 失败。通过挖掘 github 源代码,我发现了问题的根源:

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle,
                                                out SafeFileHandle InterfaceHandle);

经过编辑以适应并使问题更加明显。第二个参数的类型不正确,该函数不返回 kernel32 句柄,因此将其包装在 SafeFileHandle 中是不正确的。这是一个不透明的句柄, native api 声明中的 WINUSB_INTERFACE_HANDLE,通常是一个指针。只有一种正确的关闭方法,您必须调用 WinUsb_Free()。代码这样做了,但调用 CloseHandle 是不正确的,注定会失败。 SafeFileHandle 提供的 CloseHandle() 调用同样会失败,您可能还没有做到这一点。

将参数类型更改为 IntPtr。这需要更改其他几处代码,主要是在 UsbInterface 类中。同样将其 Handle 属性类型更改为 IntPtr。删除其 Dispose() 方法中的 CloseHandle() 调用。编写您自己的 SafeHandle 派生类来包装它是另一种方法,然后您将覆盖 ReleaseHandle() 以调用 WinUsb_Free()。

关于C# WinUSB 无法在接口(interface)上调用 CloseHandle,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54189056/

相关文章:

Android 如何以编程方式释放声明的 USB 接口(interface)

c# - 如何对生成线程的方法进行单元测试?

c# - PInvoke - 找不到指定的模块。如何检查缺少的依赖项?

c++ - 如何确定 SSD 驱动器是固定驱动器还是连接到 USB?

c++ - 如何在 Linux 上重现 Windows winusb 驱动程序的功能?我还需要这样做吗?

android - Windows PC 作为 USB 主机通过 USB 与 Android 设备通信

c++ - 编译使用 WinUsb 的应用程序

c# - 如何将标签或按钮准确地放置在表单的中间?

c# - 比较 IEnumerable<T> 的类型

到 USB 调制解调器的 PHP 命令