- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
精简版:
在我正在测试的系统中,USB 设备和电缆应始终连接在相同的连接器上,因此在 USBview 应用程序中查看时,USB 树看起来应该始终相同。但由于我没有从该树中识别设备的信息,我仍然无法判断设备 X 是否在现场实际连接到 X。但是,我可以让设备 X 开始发送输入消息。所以我希望能够通过 USB 设备生成的输入消息来验证所有设备和布线是否正确连接。
带有更多详细信息的长版:我想测试所有 USB 电缆是否正确连接到系统中预先指定的连接器。要正确执行此操作,我需要有关系统中 USB 输入设备连接到的端口的信息。我知道这是可行的,因为我已经调试了 USBview 示例应用程序(它可以在 here 中找到)。不幸的是,我事先不知道连接的设备,所以我只能测试端口号并让设备生成输入消息来帮助我检查布线是否正确连接。为了做到这一点,我需要找出生成的消息的来源(它是设备位置信息)。这是我迷路的地方。
我已经订阅了从键盘和鼠标接收 WM_INPUT 消息,我得到了这些消息。我还通过从消息中获取原始设备名称(或路径,更多信息 here )并使用它在注册表中从 HKLM\SYSTEM\CurrentControlSet\Enum\USB
查找位置信息来获取生成消息的设备的位置信息。 .要查找位置信息,我首先找到以输入设备的硬件 ID(供应商 ID 或 VID 和产品 ID 或 PID)命名的子项,该子项也是原始设备路径的一部分,然后枚举其所有子项(实例 ID),直到找到一个带有 ParentIdPrefix
具有与实例 ID 匹配的值,该 ID 也是原始设备路径的一部分。对于那个子键,我查找 LocationInformation
的值(格式化 Port_#000X.Hub_#000Y
)。这适用于连接到我的笔记本电脑或扩展坞的键盘和鼠标,即使以随机顺序重新连接设备,我从输入消息中获得的端口和集线器编号也是一致且可靠的,但是当我以随机方式重新连接设备时,它不再一致和可靠在它们之间添加 USB 集线器。集线器编号似乎取决于集线器连接到系统的顺序,例如先连接 A,然后连接 B,结果 A 为 Port_#0001.Hub_#0004,B 为 Port_#0001.Hub_#0005,但连接它们反过来会导致 A 的 Port_#0001.Hub_#0005 和 B 的 Port_#0001.Hub_#0004(这是我的应用程序在下次收到输入消息时报告的位置信息)。尽管 USBview 示例应用程序报告这些设备的集线器和端口号一致(即使重新连接和重新启动),所以我查找位置信息时肯定有错误......但是什么?显然我不能仅仅依靠注册表来获取位置信息(我知道 USBview 使用 SetupDi* 调用和它自己的枚举例程)。所以如何可靠地找到与生成 WM_INPUT 消息的设备对应的 USBview 中的位置信息? 例如,我可以将在 WM_INPUT 消息中获得的原始输入设备句柄与我可以用来获取位置信息的任何内容进行匹配吗?
这是我到目前为止的代码......
...在 InitInstance 中:
// register for raw input device input messages
RAWINPUTDEVICE rid[2];
rid[0].usUsagePage = 0x01;
rid[0].usUsage = 0x06; // keyboard
rid[0].dwFlags =
RIDEV_DEVNOTIFY | // receive device arrival / removal messages
RIDEV_INPUTSINK; // receive messages even if not in foreground
rid[0].hwndTarget = hWnd;
rid[1].usUsagePage = 0x01;
rid[1].usUsage = 0x02; // mouse
rid[1].dwFlags =
RIDEV_DEVNOTIFY |
RIDEV_INPUTSINK;
rid[1].hwndTarget = hWnd;
if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE)
{
DisplayLastError(TEXT("Failed to register for raw input devices"), hWnd);
return FALSE;
}
return TRUE;
case WM_INPUT:
{
LONG lResult = Input(hWnd, lParam, ++ulCount);
if (lResult != 0) PostQuitMessage(lResult);
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
LONG Input(HWND hWnd, LPARAM lParam, ULONG ulCount)
{
UINT dwSize = 0;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
{
MessageBox(hWnd, TEXT("Unable to allocate buffer for raw input data!"), TEXT("Error"), MB_OK);
return 1;
}
std::unique_ptr<BYTE, void(*)(LPBYTE)> lpbd(lpb, [](LPBYTE p) { delete[] p; });
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
{
MessageBox(hWnd, TEXT("GetRawInputData returned incorrect size!"), TEXT("Error"), MB_OK);
return 1;
}
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEKEYBOARD && raw->data.keyboard.VKey == 0x51)
{
OutputDebugString(TEXT("Q for Quit was pressed, exiting application\n"));
return 1;
}
TCHAR ridDeviceName[256];
dwSize = 256;
UINT dwResult = GetRawInputDeviceInfo(raw->header.hDevice, RIDI_DEVICENAME, &ridDeviceName, &dwSize);
if (dwResult == 0 || dwResult == UINT(-1))
{
return DisplayLastError(TEXT("Failed to get raw input device info"), hWnd);
}
const std::wstring devicePath(ridDeviceName);
OutputDebugString((std::to_wstring(ulCount) + L": Received WM_INPUT for USB device with path: " + devicePath + L"\n").c_str());
HKEY hKey;
std::wstring keypath = L"SYSTEM\\CurrentControlSet\\Enum\\USB";
LONG lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keypath.c_str(), 0, KEY_READ, &hKey);
if (lResult != ERROR_SUCCESS)
{
keypath = keypath.insert(0, L"Failed to open registry key");
return DisplayLastError(&keypath[0], lResult, hWnd);
}
std::unique_ptr<HKEY__, void(*)(HKEY)> hkeyd(hKey, [](HKEY h) { RegCloseKey(h); });
DWORD dwIndex = 0;
TCHAR subKeyName[256];
do
{
DWORD dwSubKeyNameLength = 256;
lResult = RegEnumKeyEx(hKey, dwIndex++, subKeyName, &dwSubKeyNameLength, NULL, NULL, NULL, NULL);
if (lResult != ERROR_SUCCESS && lResult != ERROR_NO_MORE_ITEMS)
{
keypath = keypath.insert(0, L"Failed to enumerate registry key");
return DisplayLastError(&keypath[0], lResult, hWnd);
}
if (lResult == ERROR_SUCCESS && devicePath.find(subKeyName) != -1)
{
const std::wstring hardwareId(subKeyName);
keypath += L"\\" + hardwareId;
HKEY hSubKey;
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keypath.c_str(), 0, KEY_READ, &hSubKey);
if (lResult != ERROR_SUCCESS)
{
keypath = keypath.insert(0, L"Failed to open registry key");
return DisplayLastError(&keypath[0], lResult, hWnd);
}
std::unique_ptr<HKEY__, void(*)(HKEY)> hsubkeyd(hSubKey, [](HKEY h) { RegCloseKey(h); });
// \\?\HID#VID_046D&PID_C016#7&d0f899c&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
// vendorID productID ParentIdPrefix (without the &0000)
// \\?\HID#VID_413C&PID_2003#7&2a634b73&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}
// DeviceClass Guid, leads to prefixed info in registry
DWORD dwSubIndex = 0;
do
{
dwSubKeyNameLength = 256;
lResult = RegEnumKeyEx(hSubKey, dwSubIndex++, subKeyName, &dwSubKeyNameLength, NULL, NULL, NULL, NULL);
if (lResult != ERROR_SUCCESS && lResult != ERROR_NO_MORE_ITEMS)
{
keypath = keypath.insert(0, L"Failed to enumerate registry key");
return DisplayLastError(&keypath[0], lResult, hWnd);
}
if (lResult == ERROR_SUCCESS)
{
std::wstring targetkeypath = keypath + L"\\" + subKeyName;
HKEY hTargetKey;
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, targetkeypath.c_str(), 0, KEY_READ, &hTargetKey);
if (lResult != ERROR_SUCCESS)
{
targetkeypath = targetkeypath.insert(0, L"Failed to open registry key");
return DisplayLastError(&targetkeypath[0], lResult, hWnd);
}
std::unique_ptr<HKEY__, void(*)(HKEY)> htargetkeyd(hTargetKey, [](HKEY h) { RegCloseKey(h); });
TCHAR valueBuffer[256];
DWORD dwBufferSize = 256;
lResult = RegQueryValueEx(hTargetKey, L"ParentIdPrefix", 0, NULL, (LPBYTE)valueBuffer, &dwBufferSize);
if (lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND)
{
targetkeypath = targetkeypath.insert(0, L"Failed to get registry value of ParentIdPrefix for key");
return DisplayLastError(&targetkeypath[0], lResult, hWnd);
}
if (lResult == ERROR_SUCCESS && devicePath.find(valueBuffer) != -1)
{
dwBufferSize = 256;
lResult = RegQueryValueEx(hTargetKey, L"LocationInformation", 0, NULL, (LPBYTE)valueBuffer, &dwBufferSize);
if (lResult != ERROR_SUCCESS)
{
targetkeypath = targetkeypath.insert(0, L"Failed to get registry value of LocationInformation for key");
return DisplayLastError(&targetkeypath[0], lResult, hWnd);
}
OutputDebugString((std::to_wstring(ulCount) + L": " + hardwareId + L" is located at: " + valueBuffer + L"\n").c_str());
}
}
}
while (lResult == ERROR_SUCCESS || lResult == ERROR_FILE_NOT_FOUND);
}
}
while (lResult == ERROR_SUCCESS);
return ERROR_SUCCESS; // non-0 return codes indicate failure
}
SetupDiGetDeviceRegistryProperty
获取位置信息但这只是向我显示了我之前从注册表中获得的相同位置信息。 USBview 示例应用程序必须滚动它自己的枚举,一旦我发现它基于什么,我将使用它作为位置信息,而不是注册表报告的位置信息。我非常想知道为什么 USBview 示例应用程序报告 USB 连接的可靠端口编号(以及基于什么?)但系统在注册表中维护的位置信息似乎取决于连接顺序?
最佳答案
如果集线器的驱动程序正确设置了设备所连接的 USB 端口号,则可以在地址值的注册表中找到它。早期的瑞萨 USB3 驱动程序没有。您可以通过我的增强版USBview,UsbTreeView检查地址值是否设置正确。 .
我不知道它究竟来自哪里,但对于任何 USB 设备和 USB 集线器 CM_Get_DevInst_Registry_Property(CM_DRP_ADDRESS) 或 SetupDiGetDeviceRegistryProperty(SPDRP_ADDRESS) 提供 USB 端口号。
USBview 使用 USB API 使用自下而上的方法。由于您从设备的 DevicePath 开始,使用设置 API 的自下而上的方法更方便:
您需要设备的 DEVINST 通过 CM_Get_Parent 向上走设备树并读取每个设备的地址,直到您点击 USB 根集线器或其主机 Controller 。因为只有 DevicePath,所以首先需要设备的 InterfaceClassGuid。您可以通过 SetupDiOpenDeviceInterface 获得它。
使用 InterfaceClassGuid,您可以通过 SetupDiGetClassDevs 获得设备列表。通过 SetupDiEnumDeviceInterfaces(提供 DevicePath)请求每个设备索引,直到您点击您的设备或它返回 FALSE。
如果你点击你的设备,你也会得到 DevInst 并到达 CM_ API 的世界,在那里你可以通过 CM_Get_Parent(&DevInstParent, DevInst) 向上走设备树。您的 HID 设备的第一个父设备可能是它的 USB 设备,其父设备是 USB 标准集线器或 USB 根集线器。
我从未见过具有 USB 硬件序列号的 USB 标准集线器,因此当它连接到新位置时,Windows 会为其创建一个新设备实例。
您所能得到的只是它的设备实例 ID (CM_Get_Device_ID),其中有一个固定部分,如 USB\VID_05E3&PID_0608,以及每个新实例的末尾生成部分,如 5&130B8FC2&0&3。如果您的设备树没有改变,那么这应该足够了。
USB 端口号不是任意的,它们是固定的,因此 UsbTreeView 显示为“端口链”的内容是固定的,并给出了几乎完整的位置信息。作为主机 Controller 的编号,UsbTreeView 在 GUID_DEVINTERFACE_USB_HOST_CONTROLLER SetupDi 枚举中使用其索引。添加或删除主机 Controller 时,这可能会发生变化。因此,与其枚举索引,其设备实例 ID 在这里可能是更好的选择。
USB 端口号在硬件中,因此它们不会更改。
关于c++ - 查找生成 WM_INPUT 消息的设备的位置信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23954997/
我正在尝试使用以下 keytool 命令为我的应用程序生成 keystore : keytool -genkey -alias tomcat -keystore tomcat.keystore -ke
编辑:在西里尔正确解决问题后,我注意到只需将生成轴的函数放在用于生成标签的函数下面就可以解决问题。 我几乎读完了 O'Reilly 书中关于 D3.js 的教程,并在倒数第二页上制作了散点图,但是当添
虽然使用 GraphiQL 效果很好,但我的老板要求我实现一个用户界面,用户可以在其中通过 UI 元素(例如复选框、映射关系)检查呈现给他们的元素并获取数据,这样做将为该人生成 graphql 输入,
我尝试在 Netbean 6.8 中使用 ws-import 生成 Java 类。我想重新生成 jax-ws,因为在 ebay.api.paypalapi 包中发现了一个错误(我认为该错误是由于 Pa
我有一个 perl 脚本,它获取系统日期并将该日期写入文件名。 系统日期被分配给 TRH1 变量,然后它被设置为一个文件名。 $TRH1 =`date + %Y%m%d%H%M`; print "TR
我是 Haskell 的新手,需要帮助。我正在尝试构建一种必须具有某种唯一性的新数据类型,因此我决定使用 UUID 作为唯一标识符: data MyType = MyType { uuid ::
我制作了一个脚本,它可以根据 Mysql 数据库中的一些表生成 XML。 该脚本在 PHP 中运行。 public function getRawMaterials($apiKey, $format
所以这是我的项目中的一个问题。 In this task, we will use OpenSSL to generate digital signatures. Please prepare a f
我在 SAS LIFEREG 中有一个加速故障时间模型,我想绘制它。因为 SAS 在绘图方面非常糟糕,我想实际重新生成 R 中曲线的数据并将它们绘制在那里。 SAS 提出了一个尺度(在指数分布固定为
我正在为 Django 后端制作一个样板,并且我需要能够使它到达下一个下载它的人显然无法访问我的 secret key 的地方,或者拥有不同的 key 。我一直在研究一些选项,并在这个过程中进行了实验
我正在创建一个生成采购订单的应用程序。我可以根据用户输入的详细信息创建文本文件。我想生成一个看起来比普通文本文件好得多的 Excel。有没有可以在我的应用程序中使用的开源库? 最佳答案 目前还没有任何
我正在尝试使用 ScalaCheck 为 BST 创建一个 Gen,但是当我调用 .sample 方法时,它给了我 java.lang.NullPointerException。我哪里错了? seal
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我尝试编写一些代码,例如(在verilog中): parameter N = 128; if (encoder_in[0] == 1) begin 23 binary_out = 1;
我正忙于在 Grails 项目中进行从 MySQL 到 Postgres 的相当复杂的数据迁移。 我正在使用 GORM 在 PostGres 中生成模式,然后执行 MySQL -> mysqldump
如何使用纯 XSLT 生成 UUID?基本上是寻找一种使用 XSLT 创建独特序列的方法。该序列可以是任意长度。 我正在使用 XSLT 2.0。 最佳答案 这是一个good example 。基本上,
我尝试安装.app文件,但是当我安装并单击“同步”(在iTunes中)时,我开始在设备上开始安装,然后停止,这是一个问题,我不知道在哪里,但我看到了我无法解决的奇怪的事情: 最佳答案 似乎您没有在Xc
自从我生成 JavaDocs 以来已经有一段时间了,我确信这些选项在过去 10 年左右的时间里已经得到了改进。 我能否得到一些有关生成器的建议,该生成器将输出类似于 .Net 文档结构的 JavaDo
我想学习如何生成 PDF,我不想使用任何第三方工具,我想自己用代码创建它。到目前为止,我所看到的唯一示例是我通过在第 3 方 dll 上打开反射器查看的代码,以查看发生了什么。不幸的是,到目前为止我看
我正在从 Epplus 库生成 excel 条形图。 这是我成功生成的。 我的 table 是这样的 Mumbai Delhi Financial D
我是一名优秀的程序员,十分优秀!