This is really answering comments on the question r.e. device detection.
Create a hidden window in your console application.
This example assumes you have a class called DevNotifier
, with an HWND hidden_wnd_;
member variable:
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);
}
You can register for notifications on hidden_wnd_.
e.g.
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
);
You'll need to implement the function to deal with the WM_DEVICE_CHANGE messages:
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;
}
In your console application you are going to have to run a message pump to get windows messages to work. If you have got other stuff to do while the application is waiting for messages then you'll need to also handle that here.
while (GetMessage(&message, NULL, 0, 0) > 0) {
TranslateMessage(&message);
DispatchMessage(&message);
}