C # WinUSB не может вызвать CloseHandle на интерфейсе - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь освободить дескриптор интерфейса USB с помощью CloseHandle. Исключение, которое я получаю:

System.Runtime.InteropServices.SEHException (0x80004005): внешний Компонент выдал исключение. в Device.Net.APICalls.CloseHandle (SafeFileHandle hObject) в Usb.Net.Windows.UsbInterface.Dispose () в C: \ GitRepos \ Device.Net \ src \ Usb.Net \ Windows \ UsbInterface.cs: строка 23
в Usb.Net.Windows.WindowsUsbDevice.Dispose () в C: \ GitRepos \ Device.Net \ SRC \ Usb.Net \ Windows \ WindowsUsbDevice.cs: линия 131

Я пытаюсь сделать это в методе Dispose моего класса.

Редактировать фон: Причина, по которой я пытаюсь это сделать, заключается в том, что мой код дает сбой при втором запуске. Согласно этой статье , я должен вызвать CloseHandle на дескрипторе устройства, которое я создал с помощью CreateFile. В любом случае это сделано в моем коде, потому что дескриптор устройства удаляется, потому что это SafeFileHandle. Но кто-то сказал мне, что мне нужно вызвать CloseHandle на дескрипторе для интерфейса. Я не знаю, правда ли это или нет. Я пытаюсь сделать это, чтобы исключить возможность того, что не вызов CloseHandle является причиной ошибки. Основываясь на других комментариях и исследованиях, я теперь считаю, что это было ошибкой и достаточно вызова WinUsb_Free. Это правильно?

Ответ Ханса Пассанта, приведенный ниже, говорит мне, чтобы я удалил вызов CloseHandle, но, как я уже отмечал в комментариях, оригинальный код (в master) никогда не вызывал CloseHandle. Конечно, удаление вызова будет работать, но это не вопрос. Вопрос, приведенный ниже: Как происходит выпуск интерфейса USB с API-интерфейсом WinUSB? . Это просто для вызова 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;
    }

Из 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 (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, но метод Dispose для SafeFileHandle выдает мне то же сообщение об ошибке. Это говорит мне о том, что метод Dispose SafeFileHandle, вероятно, также вызывает CloseHandle, и возникает та же проблема.

Другие люди упоминали, что я должен использовать IntPtr вместо SafeFileHandle. Итак, я попытался использовать IntPtr в интерфейсе для CloseHandle, но проблема та же: enter image description here

Вот определение WinUsb_Initialize

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

Как происходит выпуск интерфейса USB с WinUSB API? Есть ли что-то, что мне нужно сделать по-другому в C #? Почему возникла эта ошибка?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Я думаю, что ответ на этот вопрос заключается в том, что нет необходимости вызывать CloseHandle через интерфейс USB. Согласно методу 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");
}

Эта статья довольно ясно об этом.

  • CloseHandle, чтобы освободить дескриптор, созданный CreateFile, как описано в шаге 1.
  • WinUsb_Free для освобождения дескриптора интерфейса WinUSB для устройства, который возвращается WinUsb_Initialize.

Ганс Пассант также рекомендовал:

Удалить вызов CloseHandle () в его методе Dispose ()

Также от Ганса Пассанта:

Тип 2-го аргумента неверен, функция не вернуть дескриптор kernel32, поэтому его перенос в SafeFileHandle невозможен правильный. Это непрозрачный дескриптор, WINUSB_INTERFACE_HANDLE в объявление нативного API, как правило, указатель под капотом. Есть только один правильный способ закрыть его, вы должны вызвать WinUsb_Free ().

Это напрямую не касается вопроса, который я задавал, но это справедливо. Причина, по которой я не смог вызвать Dispose () для дескриптора, возвращенного из WinUsb_Initialize, как указывает Ганс, заключается в том, что при этом вызову будет закрыт CloseHandle, а 2-й аргумент, возвращаемый WinUsb_Initialize, не является дескриптором kernel32, поэтому CloseHandle () просто победил ' не работает ни на что. Это просто приводит к тому, что, похоже, нет никаких указаний на то, что необходимо вызывать CloseHandle на интерфейсе. Поэтому я считаю, что проблема, с которой я сталкиваюсь (отдельная проблема), не имеет ничего общего с тем, чтобы не вызывать CloseHandle. Кажется, это проблема самой прошивки, и производитель, кажется, подтвердил это. Больше подробностей.

Примечание. Если я не прав, скажите, пожалуйста, почему я не прав, и укажите пример использования CloseHandle для закрытия ручки на интерфейсе USB.

0 голосов
/ 20 января 2019

CloseHandle () завершается ошибкой, когда дескриптор не является правильным дескриптором kernel32 или дескриптор уже закрыт. Покопавшись в исходном коде github, я обнаружил, с чего началась эта проблема:

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

Отредактировано, чтобы соответствовать и сделать проблему более заметной. Тип 2-го аргумента неверен, функция не возвращает дескриптор kernel32, поэтому его перенос в SafeFileHandle некорректен. Это непрозрачный дескриптор, WINUSB_INTERFACE_HANDLE в нативном объявлении API, обычно указатель под капотом. Есть только один правильный способ закрыть его, вы должны вызвать WinUsb_Free (). Код делает это, но также , вызывающий CloseHandle, неверен и обречен на неудачу. Вызов CloseHandle (), предоставленный SafeFileHandle, также завершится неудачно, вы, вероятно, еще не достигли этого.

Измените тип аргумента на IntPtr. Это требует нескольких других изменений кода, прежде всего в классе UsbInterface. Аналогично измените его тип свойства Handle на IntPtr. Удалите вызов CloseHandle () в его методе Dispose (). Написание собственного класса, производного от SafeHandle, для его переноса - это еще один способ. Затем необходимо переопределить ReleaseHandle () для вызова WinUsb_Free ().

...