I am trying to release a handle to the USB interface with CloseHandle. The exception I get is:
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
I am trying to do this in the Dispose method of my class.
Edit Background: The reason I am trying to do this is that my code is crashing the second time I run it. According to this article, I must call CloseHandle on the handle to the device that I created with CreateFile. This is done in my code anyway because the device's handle is getting disposed because it is a SafeFileHandle. But, someone told me that I need to call CloseHandle on the handle for the interface. I don't know whether this is true or not. I am attempting to do this to rule out the possibility that not calling CloseHandle is the reason for the bug. Based on other comments and research, I now believe that this was a mistake and calling WinUsb_Free should suffice. Is this correct?
Hans Passant's answer below is telling me to delete the call to CloseHandle, but as I've pointed out in the comments, the original code (in master) never called CloseHandle in the first place. Of course removing the call will work, but this isn't the question. The question as below is: What is the process for releasing a USB interface with the WinUSB API?. Is it simply to call WinUsb_Free? That's what all the information I have is leading me to believe.
This is the original dispose method from before I asked this question. It does not have the call to CloseHandle.
public void Dispose()
{
if (_IsDisposed) return;
_IsDisposed = true;
var isSuccess = WinUsbApiCalls.WinUsb_Free(Handle);
WindowsDeviceBase.HandleError(isSuccess, "Interface could not be disposed");
}
From 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;
}
From 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 Call Definition (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);
I have also tried simply disposing of the handle because it is a SafeFileHandle, but the Dispose method of SafeFileHandle gives me the same error message. That suggests to me that SafeFileHandle's Dispose method is probably calling CloseHandle as well, and the same problem is occurring.
Other people have mentioned I should use IntPtr instead of SafeFileHandle. So, I have tried using IntPtr on the interface for CloseHandle, but the problem is the same:
Here is the definition of WinUsb_Initialize
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out IntPtr InterfaceHandle);
What is the process for releasing a USB interface with the WinUSB API? Is there something I need to do differently in C#? Why would this error come up?
Dispose
implementation is faulty. Part of the contract forIDisposable
is that it's legal to callDispose
multiple times on the same object. You need to keep track of whetherWinUSB_Free
has already been called and not call it again. – Pt