これは、デバイス検出に関する質問に対するコメントに本当に答えています。
コンソール アプリケーションで隠しウィンドウを作成します。
DevNotifier
この例では、HWND hidden_wnd_;
メンバー変数を持つ というクラスがあることを前提としています。
static TCHAR const s_window_class[] = _T("Device notification window");
static TCHAR const* const s_window_title = s_window_class;
LRESULT CALLBACK
DevNotifierWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
) {
DevNotifier* dn = (DevNotifier*) ::GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (message)
{
case WM_DEVICECHANGE:
dn->onWM_DEVICECHANGE(
wParam,
lParam
);
break;
default:
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void
DevNotifier::createHiddenWindow()
{
HINSTANCE hinstance = ::GetModuleHandle(NULL);
if ((hinstance == 0) || (hinstance == INVALID_HANDLE_VALUE))
{
throw Exception("Failed to get application instance handle.");
}
// register window class
WNDCLASSEX wcex;
::memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = 0;
wcex.lpfnWndProc = &DevNotifierWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hinstance;
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = s_window_class;
wcex.hIconSm = 0;
(void) ::RegisterClassEx(&wcex);
// Create the window
hidden_wnd_ = ::CreateWindow(
s_window_class,
s_window_title,
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hinstance,
NULL
);
if (!hidden_wnd_) {
throw Exception("Failed to create device notification window");
}
#ifdef _WIN64
::SetWindowLongPtr(static_cast<HWND>(hidden_wnd_), GWLP_USERDATA, (LONG_PTR)this);
#else
::SetWindowLongPtr(static_cast<HWND>(hidden_wnd_), GWLP_USERDATA, (LONG)this);
#endif
::ShowWindow(static_cast<HWND>(hidden_wnd_), SW_HIDE);
}
hidden_wnd_ で通知を登録できます。
例えば
DEV_BROADCAST_DEVICEINTERFACE filter;
ZeroMemory(&filter, sizeof(filter));
filter.dbcc_size = sizeof(filter);
filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
filter.dbcc_classguid = /* SOME INTERFACE GUID */;
HDEVNOTIFY hdn = ::RegisterDeviceNotification(
hidden_wnd_,
&filter,
DEVICE_NOTIFY_WINDOW_HANDLE
);
WM_DEVICE_CHANGE メッセージを処理する関数を実装する必要があります。
bool
DevNotifier::onWM_DEVICECHANGE(WPARAM wparam, LPARAM lparam)
{
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*)lparam;
// Note dbh will NOT always be valid, depending upon the value of wparam.
if (wparam == DBT_DEVNODES_CHANGED) {
// Do some stuff here
return true;
}
else if (wparam == DBT_DEVICEARRIVAL) {
DEV_BROADCAST_HDR* hdr = (DEV_BROADCAST_HDR*)lparam;
if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DEV_BROADCAST_DEVICEINTERFACE* devinterface =
(DEV_BROADCAST_DEVICEINTERFACE*)hdr;
// Do some stuff here
}
}
else if (wparam == DBT_DEVICEREMOVEPENDING) {
}
else if (wparam == DBT_DEVICEREMOVECOMPLETE) {
HANDLE h = INVALID_HANDLE_VALUE;
DEV_BROADCAST_HDR* phdr = (DEV_BROADCAST_HDR*) lparam;
if (phdr->dbch_devicetype == DBT_DEVTYP_HANDLE) {
DEV_BROADCAST_HANDLE* pdbh = (DEV_BROADCAST_HANDLE*) lparam;
h = pdbh->dbch_handle;
}
else if (phdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DEV_BROADCAST_DEVICEINTERFACE* devinterface =
(DEV_BROADCAST_DEVICEINTERFACE*)phdr;
// Do some stuff here
}
// Maybe do some stuff here too.
}
return false;
}
コンソール アプリケーションでは、Windows メッセージを機能させるためにメッセージ ポンプを実行する必要があります。アプリケーションがメッセージを待っている間に他のことをする必要がある場合は、それもここで処理する必要があります。
while (GetMessage(&message, NULL, 0, 0) > 0) {
TranslateMessage(&message);
DispatchMessage(&message);
}