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

Mel*_*per 6 c# usb winusb safefilehandle

我试图用CloseHandle释放USB接口的句柄.我得到的例外是:

System.Runtime.InteropServices.SEHException(0x80004005):外部组件引发了异常.位于Usb.Net.Windows.UsbInterface.Dispose()的Device.Net.APICalls.CloseHandle(SafeFileHandle hObject)位于C:\ GitRepos\Device.Net\src\Usb.Net\Windows\UsbInterface.cs:
位于Usb的第23行C:\ GitRepos\Device.Net\src\Usb.Net\Windows\WindowsUsbDevice.cs中的.Net.Windows.WindowsUsbDevice.Dispose():第131行

我试图在我班级的Dispose方法中这样做.

编辑背景:我试图这样做的原因是我的代码在第二次运行时崩溃了.根据这篇文章,我必须在我使用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");
    }
Run Code Online (Sandbox Code Playgroud)

来自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;
    }
Run Code Online (Sandbox Code Playgroud)

来自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");
    }
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

我也试过简单地处理句柄,因为它是一个SafeFileHandle,但SafeFileHandle的Dispose方法给了我相同的错误信息.这告诉我SafeFileHandle的Dispose方法也可能调用CloseHandle,同样的问题正在发生.

其他人提到我应该使用IntPtr而不是SafeFileHandle.所以,我尝试在CloseHandle接口上使用IntPtr,但问题是一样的: 在此输入图像描述

这是WinUsb_Initialize的定义

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

使用WinUSB API释放USB接口的过程是什么?在C#中我是否需要做些不同的事情?为什么会出现这个错误?

Han*_*ant 10

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

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

编辑以适应并使问题更加明显.第二个参数的类型不正确,该函数不返回kernel32句柄,因此将其包装在SafeFileHandle中是不正确的.这是一个不透明的句柄,本机api声明中的WINUSB_INTERFACE_HANDLE,通常是引擎盖下的指针.只有一种正确的方法可以关闭它,你必须调用WinUsb_Free().该代码这样做,但呼吁CloseHandle的是不正确的,也是注定要失败的.SafeFileHandle提供的CloseHandle()调用同样会失败,你可能还没有那么远.

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

  • 我可以再次重复你必须调用WinUsb_Free()而不是CloseHandle,但这只会导致非常难以沟通.我怀疑你没有写这段代码,不明白它是如何工作的,因此不相信我的建议,请咨询任何人,以解决这个问题. (3认同)

Mel*_*per 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");
}
Run Code Online (Sandbox Code Playgroud)

这篇文章对此说得非常清楚。

  • CloseHandle 以释放 CreateFile 创建的句柄,如步骤 1 中所述。
  • WinUsb_Free 释放设备的 WinUSB 接口句柄,该句柄由 WinUsb_Initialize 返回。

汉斯·帕桑特还推荐:

删除其 Dispose() 方法中的 CloseHandle() 调用

另外,来自汉斯·帕桑:

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

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

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