C# WinUSB 无法在接口上调用 CloseHandle
C# WinUSB Can't Call CloseHandle on Interface
我正在尝试使用 CloseHandle 释放 USB 接口的句柄。我得到的例外是:
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
我正在尝试在 class 的 Dispose 方法中执行此操作。
编辑背景:
我尝试这样做的原因是我的代码在我第二次 运行 时崩溃了。根据此 article,我必须在我使用 CreateFile 创建的设备的句柄上调用 CloseHandle。无论如何,这是在我的代码中完成的,因为设备的句柄正在被处理,因为它是一个 SafeFileHandle。但是,有人告诉我,我需要在接口的句柄上调用 CloseHandle。我不知道这是不是真的。我试图这样做是为了排除不调用 CloseHandle 是错误原因的可能性。根据其他评论和研究,我现在认为这是一个错误,调用 WinUsb_Free 应该就足够了。这是正确的吗?
Hans Passant 在下面的回答告诉我删除对 CloseHandle 的调用,但正如我在评论中指出的那样,原始代码(在 master 中)从来没有首先调用 CloseHandle。当然,删除呼叫会起作用,但这不是问题所在。下面的问题是:用WinUSBAPI释放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;
}
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释放USB接口的过程是什么API?我需要在 C# 中做些不同的事情吗?为什么会出现这个错误?
当句柄不是正确的 kernel32 句柄或句柄已经关闭时,CloseHandle() 失败。深入研究 github 源代码,我发现了问题的根源:
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle,
out SafeFileHandle InterfaceHandle);
进行了编辑以适应并使问题更加明显。第二个参数的类型不正确,该函数没有 return kernel32 句柄,因此将其包装在 SafeFileHandle 中是不正确的。这是一个不透明的句柄,本机 api 声明中的 WINUSB_INTERFACE_HANDLE,通常是一个指针。只有一种正确的关闭方式,必须调用WinUsb_Free()。代码这样做了,但是 also 调用 CloseHandle 是不正确的,注定会失败。 SafeFileHandle 提供的 CloseHandle() 调用同样会失败,您可能还没有做到这一点。
将参数类型更改为 IntPtr
。这需要更改其他几处代码,主要是在 UsbInterface class 中。同样将其 Handle 属性 类型更改为 IntPtr。删除其 Dispose() 方法中的 CloseHandle() 调用。编写您自己的 SafeHandle 派生 class 来包装它是另一种方法,然后您将覆盖 ReleaseHandle() 以调用 WinUsb_Free().
我认为这个问题的答案是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 to release the handle that was created by CreateFile, as described in the step 1.
- WinUsb_Free to release the WinUSB interface handle for the device, which is returned by WinUsb_Initialize.
Hans Passant 还推荐:
Delete the CloseHandle() call in its Dispose() method
此外,来自 Hans Passant:
The type of the 2nd argument is incorrect, the function does not
return a kernel32 handle so wrapping it in SafeFileHandle is not
correct. This is an opaque handle, a WINUSB_INTERFACE_HANDLE in the
native api declaration, typically a pointer under the hood. There is
only one correct way to close it, you must call WinUsb_Free().
这并没有直接涉及我提出的问题,但这是一个公平的观点。正如 Hans 指出的那样,我无法在从 WinUsb_Initialize 返回的句柄上调用 Dispose() 的原因是这样做会在后台调用 CloseHandle,而 WinUsb_Initialize 返回的第二个参数不是 kernel32 handle 所以 CloseHandle() 无论如何都不会工作。这只是导致似乎没有任何迹象表明有必要在界面上调用 CloseHandle。所以,我相信我遇到的问题(单独的问题)与不调用 CloseHandle 无关。这似乎是固件本身的问题,制造商似乎已经确认了这一点。更多细节即将到来。
注意:如果我错了,请告诉我为什么我错了,并指出一个示例,其中 CloseHandle 用于关闭 USB 接口上的句柄.
我正在尝试使用 CloseHandle 释放 USB 接口的句柄。我得到的例外是:
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
我正在尝试在 class 的 Dispose 方法中执行此操作。
编辑背景: 我尝试这样做的原因是我的代码在我第二次 运行 时崩溃了。根据此 article,我必须在我使用 CreateFile 创建的设备的句柄上调用 CloseHandle。无论如何,这是在我的代码中完成的,因为设备的句柄正在被处理,因为它是一个 SafeFileHandle。但是,有人告诉我,我需要在接口的句柄上调用 CloseHandle。我不知道这是不是真的。我试图这样做是为了排除不调用 CloseHandle 是错误原因的可能性。根据其他评论和研究,我现在认为这是一个错误,调用 WinUsb_Free 应该就足够了。这是正确的吗?
Hans Passant 在下面的回答告诉我删除对 CloseHandle 的调用,但正如我在评论中指出的那样,原始代码(在 master 中)从来没有首先调用 CloseHandle。当然,删除呼叫会起作用,但这不是问题所在。下面的问题是:用WinUSBAPI释放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;
}
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释放USB接口的过程是什么API?我需要在 C# 中做些不同的事情吗?为什么会出现这个错误?
当句柄不是正确的 kernel32 句柄或句柄已经关闭时,CloseHandle() 失败。深入研究 github 源代码,我发现了问题的根源:
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle,
out SafeFileHandle InterfaceHandle);
进行了编辑以适应并使问题更加明显。第二个参数的类型不正确,该函数没有 return kernel32 句柄,因此将其包装在 SafeFileHandle 中是不正确的。这是一个不透明的句柄,本机 api 声明中的 WINUSB_INTERFACE_HANDLE,通常是一个指针。只有一种正确的关闭方式,必须调用WinUsb_Free()。代码这样做了,但是 also 调用 CloseHandle 是不正确的,注定会失败。 SafeFileHandle 提供的 CloseHandle() 调用同样会失败,您可能还没有做到这一点。
将参数类型更改为 IntPtr
。这需要更改其他几处代码,主要是在 UsbInterface class 中。同样将其 Handle 属性 类型更改为 IntPtr。删除其 Dispose() 方法中的 CloseHandle() 调用。编写您自己的 SafeHandle 派生 class 来包装它是另一种方法,然后您将覆盖 ReleaseHandle() 以调用 WinUsb_Free().
我认为这个问题的答案是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 to release the handle that was created by CreateFile, as described in the step 1.
- WinUsb_Free to release the WinUSB interface handle for the device, which is returned by WinUsb_Initialize.
Hans Passant 还推荐:
Delete the CloseHandle() call in its Dispose() method
此外,来自 Hans Passant:
The type of the 2nd argument is incorrect, the function does not return a kernel32 handle so wrapping it in SafeFileHandle is not correct. This is an opaque handle, a WINUSB_INTERFACE_HANDLE in the native api declaration, typically a pointer under the hood. There is only one correct way to close it, you must call WinUsb_Free().
这并没有直接涉及我提出的问题,但这是一个公平的观点。正如 Hans 指出的那样,我无法在从 WinUsb_Initialize 返回的句柄上调用 Dispose() 的原因是这样做会在后台调用 CloseHandle,而 WinUsb_Initialize 返回的第二个参数不是 kernel32 handle 所以 CloseHandle() 无论如何都不会工作。这只是导致似乎没有任何迹象表明有必要在界面上调用 CloseHandle。所以,我相信我遇到的问题(单独的问题)与不调用 CloseHandle 无关。这似乎是固件本身的问题,制造商似乎已经确认了这一点。更多细节即将到来。
注意:如果我错了,请告诉我为什么我错了,并指出一个示例,其中 CloseHandle 用于关闭 USB 接口上的句柄.