我有一个非常简单的Windows应用程序,可以监听USB输入设备的到达和删除。由于某种原因,在WM_INPUT_DEVICE_CHANGE消息中传递的句柄对于到达事件始终有效,但对于删除事件几乎从不有效。在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;
在WndProc中,我的应用程序处理WM_INPUT_DEVICE_CHANGE消息,如下所示:
case WM_INPUT_DEVICE_CHANGE:
{
std::wstring action = wParam == GIDC_ARRIVAL ? L"arrival" : L"removal";
TCHAR ridDeviceName[256];
UINT dwSize = 256;
UINT dwResult = GetRawInputDeviceInfo((void*)lParam, RIDI_DEVICENAME, &ridDeviceName, &dwSize);
if (dwResult == 0 || dwResult == UINT(-1))
{
//action = action.insert(0, L"Failed to get raw input device info during device ");
//DisplayLastError(&action[0], hWnd);
// -- THIS IS WHERE DEVICE REMOVAL MESSAGES KEEP ENDING UP
OutputDebugString((L"Received WM_INPUT_DEVICE_CHANGE with parameter: " + action + L" for USB device with handle: " + std::to_wstring(lParam) + L"\n").c_str());
}
else
{
const std::wstring devicePath(ridDeviceName);
OutputDebugString((L"Received WM_INPUT_DEVICE_CHANGE with parameter: " + action + L" for USB device with path: " + devicePath + L"\n").c_str());
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
设备删除时会发生什么:GetLastError报告错误6 =句柄无效,dwResult = UINT(-1),评论意味着缓冲区不足,但dwSize仍设置为256,即使我重试缓冲区和dwSize为4096它仍然失败,dwSize仍然设置为4096,同时我也看到了lParam的负值,并且它看起来确实不是一个有效的句柄值。
我在这里做错了吗? MSDN说lParam应该有一个设备句柄,为什么它几乎永远不会有效删除设备?是否有一种不同的方法来检测应该使用的设备删除?PS:我正在通过在我的笔记本电脑,扩展坞和USB集线器上添加和删除键盘进行测试,我使用的是Windows 7 x64。我的应用程序也会监听WM_INPUT消息,但仅用于输入。
答案 0 :(得分:0)
我猜想GIDC_REMOVAL
上的句柄已经被关闭。
您可以仅在GetRawInputDeviceInfo()
上致电GIDC_ARRIVAL
并将此信息保存在某个持久的位置-例如在static std::map<HANDLE, std::wstring>
中。
如果您需要GIDC_REMOVAL
事件的此信息,可以致电map[(HANDLE)lParam]
进行请求。
也不要忘记在map.remove((HANDLE)lParam)
事件处理结束时调用GIDC_REMOVAL
,因此您将始终获得当前连接的设备句柄列表。