LibUsbDotNet:退出WPF应用程序时出错 - 安全句柄已关闭

4

在WPF应用程序中使用USB设备,我可以成功连接并发送命令到设备。设备只接收命令,没有回复,所以我只需要一个EndpointWriter来与它通信。

MyUsbFinder = new UsbDeviceFinder(vid, pid);
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
    wholeUsbDevice.SetConfiguration(1);
    wholeUsbDevice.ClaimInterface(0);
}

writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);

接着是写入设备的过程:

byte[] update = { some bytes };
int bytesWritten;

if (MyUsbDevice != null)
{
     ec = writer.Write(update, 2000, out bytesWritten);
}

除了在工作过程中USB设备被断开并重新连接之外,一切都很正常。该应用程序成功处理了这种情况,并重新连接到设备,继续成功发送命令:

public bool reconnect()
{
    //clear the info so far
    if (MyUsbDevice != null)
    {
        writer.Dispose();
        wholeUsbDevice.ReleaseInterface(0);
        wholeUsbDevice.Close();
        MyUsbDevice.Close();
        UsbDevice.Exit();
    }

    //now start over
    MyUsbFinder = new UsbDeviceFinder(vid, pid);
    MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);

当我断开/重新连接后关闭应用程序时,出现了问题。虽然该程序在与设备成功通信了相当长时间,但在退出时会出现以下异常:

System.ObjectDisposedException was unhandled
  Message="Safe handle has been closed"
  Source="mscorlib"
  ObjectName=""
  StackTrace:
       at System.StubHelpers.StubHelpers.SafeHandleC2NHelper(Object pThis, IntPtr pCleanupWorkList)
       at LibUsbDotNet.Internal.Kernel32.GetOverlappedResult(SafeHandle hDevice, IntPtr lpOverlapped, Int32& lpNumberOfBytesTransferred, Boolean bWait)
       at LibUsbDotNet.Internal.LibUsb.LibUsbAPI.GetOverlappedResult(SafeHandle interfaceHandle, IntPtr pOverlapped, Int32& numberOfBytesTransferred, Boolean wait)
       at LibUsbDotNet.Internal.OverlappedTransferContext.Wait(Int32& transferredCount, Boolean cancel)
       at LibUsbDotNet.Main.UsbTransfer.Wait(Int32& transferredCount)
       at LibUsbDotNet.Main.UsbTransfer.Dispose()
       at LibUsbDotNet.Main.UsbTransfer.Finalize()
  InnerException: 

我尝试了许多不同的Dispose和Exit方法来关闭usb设备和endpointwriter,但是迄今为止没有成功。我猜测在断开连接之前仍有一些东西保持打开状态,所以我会得到这个错误,但我不确定是什么并且也不知道如何处理。
由于这种情况只发生在关闭应用程序时,因此我甚至愿意忽略异常并让应用程序自行崩溃,但我不知道如何捕获该异常,因为Window_Closing事件返回成功后异常才会发生,所以我不能捕获它...
非常感谢您提供任何提示!

1
你这段时间解决了你的问题吗?我遇到了几乎完全相同的问题。 - Jasper
很遗憾,目前还没有。老实说,我最近没有再关注它,因为我们已经成功地隔离了设备,这样人们就不会再意外拔掉USB电缆了。如果我有时间再去看一下并找到有用的信息,我一定会更新这个问题。 - mmvsbg
我刚刚遇到了这个确切的问题。非常恼人,因为它似乎是 LibUsbDotNet 库本身的一个 bug。 - NathanAldenSr
2个回答

5

我在 Windows 服务中遇到了类似的异常。我的调用堆栈如下:

Exception Info: System.ObjectDisposedException
Stack:
   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean ByRef)
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(System.Runtime.InteropServices.SafeHandle, Boolean ByRef)
   at LibUsbDotNet.Internal.Kernel32.GetOverlappedResult(System.Runtime.InteropServices.SafeHandle, IntPtr, Int32 ByRef, Boolean)
   at LibUsbDotNet.Internal.LibUsb.LibUsbAPI.GetOverlappedResult(System.Runtime.InteropServices.SafeHandle, IntPtr, Int32 ByRef, Boolean)
   at LibUsbDotNet.Internal.OverlappedTransferContext.Wait(Int32 ByRef, Boolean)
   at LibUsbDotNet.Main.UsbTransfer.Dispose()
   at LibUsbDotNet.Main.UsbTransfer.Finalize()

为了解决这个问题,我通过添加一个检查 interfaceHandle.IsClosed 的步骤来修复了 LibUsbDotNet.Internal.LibUsb.LibUsbAPI.GetOverlappedResult() 方法。现在该方法看起来像这样:
public override bool GetOverlappedResult(SafeHandle interfaceHandle, IntPtr pOverlapped, out int numberOfBytesTransferred, bool wait)
{
    // To prevent ObjectDisposedException check if SafeHandle's been closed
    if (!interfaceHandle.IsClosed)
        return Kernel32.GetOverlappedResult(interfaceHandle, pOverlapped, out numberOfBytesTransferred, wait);
    else
    {
        numberOfBytesTransferred = 0;
        return true;
    }
}

希望这有所帮助。

肯定有帮助!我注意到你们两个都注意到的确切问题:连接和断开连接导致应用程序终止并执行析构函数时抛出此异常。 - NathanAldenSr

3

我在关闭我的WPF应用程序时遇到了“安全句柄已关闭”的ObjectDisposedException类似的问题。

我的堆栈跟踪略有不同:

System.ObjectDisposedException was unhandled  
  HResult=-2146232798  
  Message=Safe handle has been closed  
  Source=mscorlib  
  ObjectName=""  
  StackTrace:  
       at System.Threading.WaitHandle.WaitOneNative(SafeHandle waitableSafeHandle, UInt32 millisecondsTimeout, Boolean hasThreadAffinity, Boolean exitContext)  
       at System.Threading.WaitHandle.InternalWaitOne(SafeHandle waitableSafeHandle, Int64 millisecondsTimeout, Boolean hasThreadAffinity, Boolean exitContext)  
       at System.Threading.WaitHandle.WaitOne(Int32 millisecondsTimeout, Boolean exitContext)  
       at LibUsbDotNet.Main.UsbTransfer.get_IsCancelled()  
       at LibUsbDotNet.Main.UsbTransfer.Dispose()  
       at LibUsbDotNet.Main.UsbTransfer.Finalize()  
  InnerException:

我已经通过在我的传输和接收函数中添加以下代码来修复它:

然而,我已经通过在我的传输和接收函数中添加以下代码来解决了这个问题...

using (UsbEndpointWriter writer = device.OpenEndpointWriter(WriteEndpoint))
{
    UsbTransfer usbTransfer = null;

    try
    {
        // Code to do transfer here .. not shown as not pertinent here..
    }
    finally
    {
        if (usbTransfer != null)
        {
            // **** Start of code added to fix ObjectDisposedException
            if (!usbTransfer.IsCancelled || !usbTransfer.IsCompleted)
            {
                usbTransfer.Cancel();
            }
            // **** End of code added to fix ObjectDisposedException
            usbTransfer.Dispose();
        }
    }
}

希望这段代码能帮到那些在解决问题时偶然发现此问题的人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接