编辑:这个问题随着时间的推移而演变。基本问题是关于如何在 Windows 中连接和读取/写入 USB 设备。最终我在@benvoigt 的帮助下回答了这个问题。
我编写了一个 Hid 库,它可以向 Hid USB 设备写入和读取数据。它运作良好。但是,我连接的设备已从隐藏访问切换到普通 USB。连接到不同类型的设备时,Hid 代码不起作用。我现在的目标是连接到 USB 接口(与 Hid 接口相反)并对其进行读/写。
在所有访问 USB 的平台上,我们必须查询 USB 设备存在的接口,然后“声明”一个用于读写的接口。这是来自 LibUsbDotNet 示例的一些代码(LibUsb 是一个有效的 C USB 库,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 正在像这样(https://github.com/libusb/libusb/blob/c6f3866414e8deeee19e8a9f10f20bde9cb408d3/libusb/os/windows_winusb.c#L2199)实现 C 中接口/端点的开放。这是它调用初始化的地方: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();
}
您可以在此处克隆此 repo 的分支: 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#L225
我的代码有什么问题?我需要做些什么来为 WinUsb_Initialize 调用分配内存吗?
我应该如何使用 winusb.dll Windows API?我需要进行哪些 API 调用来声明和接口或端点以进行读写?
如果有人可以向我指出一个简单的 C 或 C# 示例,它可以读取和写入 USB 设备并实际工作,那真的会对我有所帮助。
WinDBG 输出:
************* 路径验证摘要 ************** 响应时间 (ms) 位置 Deferred
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: 00007ffb5ed00000 00007ffb
5ed20000
C:\WINDOWS\System32\007ffbffbx34e1b0000 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)\conhost。 exe!00007FF7169FE2AF: (caller: 00007FF7169FF414) ReturnHr(1) tid(4230) 80070578 无效的窗口句柄。模组加载:00007ffb60990000 00007ffb
60a42000
C:\WINDOWS\System32\KERNEL32.dll ModLoad: 00007ffb5f000000 00007ffb
5f192000 C:\WINDOWS\System32\gdi32full.dll ModLoad: 00007ffb60d90000 00007ffb
60f03000 C:\WINDOWS\System32\MSCTF.dll ModLoad: 00007ffb5ed80000 00007ffb
5eff3000
C:\WINDOWS\ System3 KERNELBASE.dll ModLoad: 00007ffb 60f3d000 C:\WINDOWS\System32\IMM32.DLL60610000 00007ffb
606d2000 C:\WINDOWS\System32\OLEAUT32.dll ModLoad: 00007ffb60f10000 00007ffb
************* 路径验证摘要 ************** 响应时间 (ms) 位置 Deferred
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 ModLoad62880000 00007ffb
: 00007ffb5fcc0000 00007ffb
62a6100000000007: 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 无效的窗口句柄。模组加载:00007ffb61140000 00007ffb
61191000
C:\WINDOWS\System32\shlwapi.dll ModLoad: 00007ffb60990000 00007ffb
60a42000 C:\WINDOWS\System32\KERNEL32.DLL ModLoad: 00007ffb5ec30000 00007ffb
5ec41000
C:\WINDOWS\System32\kernel.appcore.dll ModLoad: 00007ffb5ed80000 00007ffb
5eff3000 C:\WINDOWS\ System32\KERNELBASE.dll ModLoad: 00007ffb5ec10000 00007ffb
5ec2f000 C:\WINDOWS\System32\profapi.dll ModLoad: 00007ffb5ebc0000 00007ffb
5ec0c000
C:\WINDOWS\System32\powrprof.dll ModLoad: 00007ffb5ebb0000 00007ffb
5ebba000 C:\WINDOWS\System32\FLTLIB.DLL ModLoad: 00007ffb5f490000 00007ffb
5f52f000
C:\WINDOWS\System32\msvcp_win.dll ModLoad: 00007ffb5f1a0000 00007ffb
5f29a000 C:\WINDOWS\System32\ucrtbase.dll ModLoad: 00007ffb606e0000 00007ffb
60789000 C:\WINDOWS\System32\shcore.dll ModLoad: 00007ffb4e290000 00007ffb
4e4f9000
C:\WINDOWS\WinSxS\amd64_dfmicrosoft.windows.common-controls_6_165b.f6444441 .472_none_fb3f9af53068156d\comctl32.DLL ModLoad: 00007ffb5ca60000 00007ffb
5caf8000
C:\WINDOWS\system32\uxtheme.dll ModLoad: 00007ffb608f0000 00007ffb
6098e000 C:\WINDOWS\System32\msvcrt.dll ModLoad: 00007ffb601e0000 00007ffb
60304000 C:\WINDOWS\System32\RPCRT4.dll ModLoad: 00007ffb60a60000 00007ffb
60d82000
C:\WINDOWS\System32\combase.dll ModLoad: 00007ffb5fc40000 00007ffb
5fcba000 C:\WINDOWS\System32\bcryptPrimitives.dll ModLoad: 00007ffb627a0000 00007ffb
62841000 C:\WINDOWS\System3 advapi32.dll ModLoad: 00007ffb 57bc6000 C:\WINDOWS\System32\TextInputFramework.dll (3d80.256c): Break 指令异常 - 代码 80000003 (第一次机会) ntdll!LdrpDoDebuggerBreak+0x30: 00007ffb`6294c93c cc int 3610d0000 00007ffb
6112b000
C:\WINDOWS\System32\sechost.dll ModLoad: 00007ffb57b30000 00007ffb