使用WM_INPUT_DEVICE_CHANGE检测输入设备删除

时间:2014-05-30 08:16:27

标签: c++ winapi usb

我有一个非常简单的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消息,但仅用于输入。

1 个答案:

答案 0 :(得分:0)

我猜想GIDC_REMOVAL上的句柄已经被关闭。

您可以仅在GetRawInputDeviceInfo()上致电GIDC_ARRIVAL并将此信息保存在某个持久的位置-例如在static std::map<HANDLE, std::wstring>中。

如果您需要GIDC_REMOVAL事件的此信息,可以致电map[(HANDLE)lParam]进行请求。

也不要忘记在map.remove((HANDLE)lParam)事件处理结束时调用GIDC_REMOVAL,因此您将始终获得当前连接的设备句柄列表。