LibUsbDotNet: ошибка при выходе из приложения WPF - безопасный дескриптор закрыт
Работая с USB-устройством в приложении WPF, я могу успешно подключаться и отправлять команды на устройство. Устройство получает только команды, но не отвечает, поэтому все, что мне нужно, это 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-устройстве, конечной точке, но пока безуспешно. Я предполагаю, что что-то остается открытым до отключения, поэтому я получаю эту ошибку, но я не уверен, что это такое и как от него избавиться.
Так как это происходит только при закрытии приложения, я не возражаю против того, чтобы даже каким-то образом игнорировать исключение и позволить приложению умереть по частям, но я не уверен, как перехватить это исключение, когда событие Window_Closing успешно возвращается, а затем исключение происходит после этого, поэтому я не могу поймать это...
Любые советы приветствуются, спасибо!
2 ответа
У меня были подобные проблемы с "Безопасный дескриптор был закрыт" Исключение ObjectDisposedException, возникающее при закрытии моего приложения WPF.
Моя трассировка стека была немного другой:
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();
}
}
}
Надеюсь, этот фрагмент может помочь любому, кто найдет этот вопрос, пытаясь решить их проблему.
Я получил подобное исключение в службе 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()
Чтобы исправить проблему, я исправил LibUsbDotNet.Internal.LibUsb.LibUsbAPI.GetOverlappedResult()
метод, добавив проверку interfaceHandle.IsClosed
, Теперь метод выглядит так:
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;
}
}
Надеюсь, поможет.