Изменить: этот вопрос менялся со временем. Основной вопрос заключался в том, как подключиться к USB-устройству и читать / писать с него в Windows. В конце концов я ответил на вопрос с помощью @benvoigt.
Я написал библиотеку Hid, которая записывает и читает с / с Hid USB-устройств. Это работает хорошо. Однако устройство, к которому я подключаюсь, переключилось с скрытого доступа на обычный USB. Hid-код не работает при подключении к другому типу устройства. Моя цель сейчас - подключиться к интерфейсу USB (в отличие от интерфейса Hid) и читать / писать в / из него.
На всех платформах, имеющих доступ к USB, мы должны запрашивать интерфейсы, существующие для USB-устройства, а затем «запрашивать» интерфейс для чтения и записи. Вот код из образца LibUsbDotNet (LibUsb - это рабочая USB-библиотека C, а LibUsbDotNet ее обертывает) https://github.com/LibUsbDotNet/LibUsbDotNet/blob/master/src/Examples/Read.Write/ReadWrite.cs.
using (var context = new UsbContext())
{
context.SetDebugLevel(LogLevel.Info);
//Get a list of all connected devices
var usbDeviceCollection = context.List();
//Narrow down the device by vendor and pid
var selectedDevice = usbDeviceCollection.FirstOrDefault(d => d.ProductId == ProductId && d.VendorId == VendorId);
//Open the device
selectedDevice.Open();
//Get the first config number of the interface
selectedDevice.ClaimInterface(selectedDevice.Configs[0].Interfaces[0].Number);
//Open up the endpoints
var writeEndpoint = selectedDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
var readEnpoint = selectedDevice.OpenEndpointReader(ReadEndpointID.Ep01);
//Create a buffer with some data in it
var buffer = new byte[64];
buffer[0] = 0x3f;
buffer[1] = 0x23;
buffer[2] = 0x23;
//Write three bytes
writeEndpoint.Write(buffer, 3000, out var bytesWritten);
var readBuffer = new byte[64];
//Read some data
readEnpoint.Read(readBuffer, 3000, out var readBytes);
}
}
У меня такое ощущение, что LibUsb обеспечивает открытие интерфейсов / конечных точек в C следующим образом (https://github.com/libusb/libusb/blob/c6f3866414e8deeee19e8a9f10f20bde9cb408d3/libusb/os/windows_winus2rel=). Здесь вызывается Initialize: https://github.com/libusb/libusb/blob/c6f3866414e8deeee19e8a9f10f20bde9cb408d3/libusb/os/windows_winusb.c#L2225, где мой код дает сбой.
Небольшой отрывок информации: это определенно устройство WinUSB. Я вижу это здесь:
Основываясь на комментариях других людей и образце кода, я вижу, что мне нужно использовать winusb.dll. Я могу вызвать CreateFile, чтобы получить дескриптор устройства. Согласно другому образцу кода, который я видел, следующим шагом будет вызов WinUsb_Initialize. Однако, когда я вызываю это, я получаю код ошибки 8 (ERROR_NOT_ENOUGH_MEMORY). Здесь есть некоторая информация https://docs.microsoft.com/en-us/windows/desktop/api/winusb/nf-winusb-winusb_initialize. Но я не совсем понимаю, что меня просят сделать. Это мой код на данный момент:
public override async Task InitializeAsync()
{
Dispose();
if (string.IsNullOrEmpty(DeviceId))
{
throw new WindowsException($"{nameof(DeviceDefinition)} must be specified before {nameof(InitializeAsync)} can be called.");
}
_DeviceHandle = APICalls.CreateFile(DeviceId, (APICalls.GenericWrite | APICalls.GenericRead), APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, APICalls.FileAttributeNormal | APICalls.FileFlagOverlapped, IntPtr.Zero);
var errorCode = Marshal.GetLastWin32Error();
if (errorCode > 0) throw new Exception($"Write handle no good. Error code: {errorCode}");
if (_DeviceHandle.IsInvalid) throw new Exception("Device handle no good");
var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var interfaceHandle);
errorCode = Marshal.GetLastWin32Error();
if (!isSuccess) throw new Exception($"Initialization failed. Error code: {errorCode}");
IsInitialized = true;
RaiseConnected();
}
Вы можете клонировать ветку этого репо здесь: https://github.com/MelbourneDeveloper/Device.Net/tree/WindowsUsbDevice. Просто запустите проект Usb.Net.WindowsSample.
Я тоже пробовал это и получил точно такой же результат:
public override async Task InitializeAsync()
{
Dispose();
if (string.IsNullOrEmpty(DeviceId))
{
throw new WindowsException($"{nameof(DeviceDefinition)} must be specified before {nameof(InitializeAsync)} can be called.");
}
_DeviceHandle = APICalls.CreateFile(DeviceId, (APICalls.GenericWrite | APICalls.GenericRead), APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, APICalls.FileAttributeNormal | APICalls.FileFlagOverlapped, IntPtr.Zero);
var errorCode = Marshal.GetLastWin32Error();
if (errorCode > 0) throw new Exception($"Write handle no good. Error code: {errorCode}");
var interfaceHandle = new IntPtr();
var pDll = NativeMethods.LoadLibrary(@"C:\GitRepos\Device.Net\src\Usb.Net.WindowsSample\bin\Debug\net452\winusb.dll");
var pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "WinUsb_Initialize");
var initialize = (WinUsb_Initialize)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(WinUsb_Initialize));
var isSuccess = initialize(_DeviceHandle, ref interfaceHandle);
errorCode = Marshal.GetLastWin32Error();
if (!isSuccess) throw new Exception($"Initialization failed. Error code: {errorCode}");
IsInitialized = true;
RaiseConnected();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool WinUsb_Initialize(SafeFileHandle DeviceHandle, ref IntPtr InterfaceHandle);
Я твердо уверен, что что-то не так с самой реализацией WinUSB устройства. Он работает с другими библиотеками, такими как LibUsb, UWP и Android, но WinUsb, похоже, не любит. Я пробовал эту библиотеку: https://github.com/madwizard-thomas/winusbnet и это также не удается выполнить тот же вызов с тем же кодом ошибки. Строка, на которой происходит сбой и код ошибки 8, находится здесь: https://github.com/madwizard-thomas/winusbnet/blob/8f62d751a99be1e31d34b91115715d60aeff2dfc/WinUSBNet/API/WinUSBDevice.cs=
Что здесь не так с моим кодом? Что мне нужно сделать, чтобы выделить память для вызова WinUsb_Initialize?
Как мне использовать Windows API winusb.dll? Какие вызовы API мне нужно сделать, чтобы заявить и связать с конечной точкой для чтения и записи?
Было бы очень полезно, если бы кто-нибудь мог указать мне на простой пример C или C #, который читает и записывает на USB-устройство и действительно работает.
Вывод WinDBG:
************* Сводка проверки пути ************** Время отклика (мс) Местоположение отложено
srv * Путь поиска символов: srv * Исполняемый путь поиска: ModLoad: 00000236157c0000 00000236
157c8000 Usb.Net.WindowsSample.exe ModLoad: 00007ffb62880000 00007ffb
62a61000 ntdll.dll ModLoad: 00007ffb60f40000 00007ffb
610d0000 C: \ WINDOWS \ System32 \ user32.dll ModLoad: 00007ffb_732_dll WINDOWS \ C: 00007ffb_732_5ed: 00007ffb_732_5ed: 00007ffb_732_5ed : 00007ffb4e1b0000 00007ffb
4e214000 C: \ WINDOWS \ SYSTEM32 \ MSCOREE.DLL ModLoad: 00007ffb612a0000 00007ffb
612c8000 C: \ WINDOWS \ System32 \ GDI32.dll onecore \ windows \ core \ console \ open \ src \ renderer \ gdi \ invalidate.cpp. (121) exe! 00007FF7169FE2AF: (вызывающий: 00007FF7169FF414) ReturnHr (1) tid (4230) 80070578 Неверный дескриптор окна. ModLoad: 00007ffb60990000 00007ffb
60a42000
C: \ WINDOWS \ System32 \ KERNEL32.dll ModLoad: 00007ffb5f000000 00007ffb
5f192000 C: \ WINDOWS \ System32 \ gdi32full.dll ModLoad: 00007ffb60d90000 00007ffb
60f03000: C: \ WINDOWB60d90000 00007ffb
60f03000: C: \ WINDOWS_C: \ F03000: C: \ WINDOWS_3000: \ \ WINDOWS \ System32 \ KERNELBASE.dll ModLoad: 00007ffb60610000 00007ffb
606d2000 C: \ WINDOWS \ System32 \ OLEAUT32.dll ModLoad: 00007ffb60f10000 00007ffb
60f3d000 C: \ WINDOWS \ System32 \ IMM32.DLL************* Сводка проверки пути ************** Время отклика (мс) Местоположение отложено
srv * Путь поиска символов: srv * Исполняемый путь поиска: ModLoad: 00007ff7169f0000 00007ff7
16a8f000 conhost.exe ModLoad: 00007ffb61340000 00007ffb
62780000 C: \ WINDOWS \ System32 \ shell32.dll ModLoad: 00007ffb5cd80000 00007ffb
5cda9000
C: \ WINDOWS \ system32 \ dwmapi.dll ModLoad 000070000_000_dwmapi.dll: \ WINDOWS \ System32 \ cfgmgr32.dll ModLoad: 00007ffb5f530000 00007ffb
5fc3d000
C: \ WINDOWS \ System32 \ windows.storage.dll onecore \ windows \ core \ console \ open \ src \ renderer \ gdi \ invalidate.cpp (121) \ conhost .exe! 00007FF7169FE2AF: (вызывающий: 00007FF7169FF414) ReturnHr (2) tid (4230) 80070578 Неверный дескриптор окна. ModLoad: 00007ffb61140000 00007ffb
61191000
C: \ WINDOWS \ System32 \ shlwapi.dll ModLoad: 00007ffb60990000 00007ffb
60a42000 C: \ WINDOWS \ System32 \ KERNEL32.DLL ModLoad: 00007ffb5ec30000 00007ffb
5ec41000: C: \ WINDOWS_INDOWS_Core_Core_C: \ C: \ WINDOWS \ System32 \ KERNELBASE.dll ModLoad: 00007ffb5ec10000 00007ffb
5ec2f000 C: \ WINDOWS \ System32 \ profapi.dll ModLoad: 00007ffb5ebc0000 00007ffb
5ec0c000
C: \ WINDOWS \ System32 \ WINDOWS \ WINDOWS \ WINDOWS \ WINDOWS \ WINDOWS \ WINDOWS \ WINDOWS \ WINDOWS \ WINDOWS \ FIND_000 \ ModLoad: 000062880000 00007ffb
Black_DBF_DB_000: 0000_5 .DLL ModLoad: 00007ffb5f490000 00007ffb
5f52f000
C: \ WINDOWS \ System32 \ msvcp_win.dll ModLoad: 00007ffb5f1a0000 00007ffb
5f29a000 C: \ WINDOWS \ System32 \ ucrtbase.dll ModLoad: 00007ffb606e0000 00007ffb
System60789000 C: \ WINDOWS606e0000 00007ffb
System60789000 C: \ WINDOWS C: \ WINDOWS \ WinSxS \ amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.17134.472_none_fb3f9af53068156d \ comctl32.DLL ModLoad: 00007ffb5ca60000 00007ffb
5caf8000 System: \ WINDOWC_WINDOWC_WINDOWC_WINDOWC_C: \ WINDOWS_WINDOWC_WINDOWC_WINDOWC_WINDOWC_C: \ WINDOWC_WINDOWC_WINDOWC_WINDOWC_C: \ WINDOWC_WINDOWC_C: \ WINDOWC_WINDOWC_WINDOWC_C: \ WINDOWC_WINDOWC_WINDOWC_System. dll ModLoad: 00007ffb601e0000 00007ffb
603 04000 C: \ WINDOWS \ System32 \ RPCRT4.dll ModLoad: 00007ffb60a60000 00007ffb
60d82000
C: \ WINDOWS \ System32 \ combase.dll ModLoad: 00007ffb5fc40000 00007ffb
5fcba000 C: \ WINDOWS \ System32 \ bcryptPrimitives.dll advapi32.dll ModLoad: 00007ffb610d0000 00007ffb
6112b000
C: \ WINDOWS \ System32 \ sechost.dll ModLoad: 00007ffb57b30000 00007ffb
57bc6000 C: \ WINDOWS \ System32 \ TextInputFramework.dll (3d80.256c): исключение инструкции прерывания - код 80000003 (первый шанс) ntdll! LdrpDoDebuggerBreak + 0x30: 00007ffb`6294c93c cc
int 3
InterfaceHandle
должно бытьout
, а неref
, но это не должно сильно изменить вашу проблему. В остальном декларация выглядит нормально. Я не могу воспроизвести ошибку 8. Когда я пытался открыть устройства на моем ПК, я получаю только ошибку 50 (ERROR_NOT_SUPPORTED). Возможно, проблема в этом конкретном USB-устройстве Trezor. - person Simon Mourier   schedule 27.12.2018