C++ Win32 не получает DBT DEVICEARRIVAL или DBT DEVICEREMOVECOMPLETE на WM DEVICECHANGE
Я работал над обнаружением вставки/удаления USB. Я реализовал код с помощью CreateWindowEx (), передавая WNCLASSEX, который с моим оконным процессом обратного вызова. При вставке и удалении моего usb я успешно получаю сообщение WM_DEVICECHANGE, но wParam всегда устанавливается в DBT_DEVNODES_CHANGED.
Я никогда не получаю ни DBT_DEVICEARRIVAL, ни DBT_DEVICEREMOVECOMPLETE. Я использую то, что получаю, но мне действительно нужно уметь отличать устройство прибытие и удаление, так что я могу предпринять различные действия в зависимости от того, что я получаю.
Прямо сейчас мне нужно поставить таймер после получения DBT_DEVNODES_CHANGED, а затем проверить, есть ли в системе новые удаляемые файлы или их больше нет в моем списке. Я уверена, что это неправильно, поэтому решила спросить. Я бы предпочел избавиться от таймера и просто получить эти два сообщения. Это очень помогло бы мне в том, что я должен сделать. Есть предложения?
Вот код, который у меня есть для регистрации обратного вызова, а также сам обратный вызов:
Примечание: 3/12/2015: код обновлен, чтобы показать фактический GUID и определение функции DoRegisterDeviceInterfaceToHwnd ().):
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
//GUID WusbrawGUID = {0xa5dcbf10, 0x6530, 0x11d2, 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed };
//GUID WusbGUID = {0x88BAE032, 0x5A81, 0x49f0, 0xBC, 0x3D, 0xA4, 0xFF, 0x13, 0x82, 0x16, 0xD6 };
INT_PTR WINAPI WinProcCallback(HWND __hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL DoRegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND __hWnd, HDEVNOTIFY *hDeviceNotify);
bool UsbController::startNotifyUsbAddedRemoved(QString &errmsg)
{
WNDCLASSEX wndClass;
wndClass.cbSize = sizeof(wndClass);
wndClass.style = 0;
wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WinProcCallback);
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wndClass.hCursor = LoadCursor(0, IDC_ARROW);
wndClass.lpszClassName = WND_CLASS_NAME;
wndClass.lpszMenuName = NULL;
wndClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
if (!RegisterClassEx(&wndClass))
{
FormatErrorMsg("RegisterClassEx: ", errmsg);
return false;
}
HINSTANCE hInstance = (HINSTANCE)::GetModuleHandle(NULL);
__hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE | WS_EX_APPWINDOW,
WND_CLASS_NAME,
WND_APP_NAME,
WS_OVERLAPPEDWINDOW, // style
CW_USEDEFAULT, 0,
0, 0,
NULL, NULL,
hInstance,
NULL);
if ( __hWnd == NULL )
{
FormatErrorMsg("CreateWindowEx: ", errmsg);
return false;
}
return true;
}
INT_PTR WINAPI WinProcCallback(HWND __hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lRet = 1;
static HDEVNOTIFY hDeviceNotify;
static HWND hEditWnd;
static ULONGLONG msgCount = 0;
switch (message)
{
case WM_CREATE:
//
// This is the actual registration., In this example, registration
// should happen only once, at application startup when the window
// is created.
//
// If you were using a service, you would put this in your main code
// path as part of your service initialization.
//
if ( ! DoRegisterDeviceInterfaceToHwnd( WceusbshGUID, __hWnd, &hDeviceNotify) )
{
// Terminate on failure.
//ErrorHandler(TEXT("DoRegisterDeviceInterfaceToHwnd"));
ExitProcess(1);
}
//
// Make the child window for output.
//
hEditWnd = CreateWindow(TEXT("EDIT"),// predefined class
NULL, // no window title
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 0, 0, // set size in WM_SIZE message
__hWnd, // parent window
(HMENU)1, // edit control ID
(HINSTANCE) GetWindowLong(__hWnd, GWL_HINSTANCE),
NULL); // pointer not needed
if ( hEditWnd == NULL )
{
// Terminate on failure.
ExitProcess(1);
}
// Add text to the window.
SendMessage(hEditWnd, WM_SETTEXT, 0,
(LPARAM)TEXT("Registered for USB device notification...n"));
break;
case WM_SETFOCUS:
SetFocus(hEditWnd);
break;
case WM_SIZE:
// Make the edit control the size of the window's client area.
MoveWindow(hEditWnd,
0, 0, // starting x- and y-coordinates
LOWORD(lParam), // width of client area
HIWORD(lParam), // height of client area
TRUE); // repaint window
break;
case WM_DEVICECHANGE:
{
//
// This is the actual message from the interface via Windows messaging.
// This code includes some additional decoding for this particular device type
// and some common validation checks.
//
// Note that not all devices utilize these optional parameters in the same
// way. Refer to the extended information for your particular device type
// specified by your GUID.
//
// Output some messages to the window.
UsbController *pusbctl;
switch (wParam)
{
case DBT_DEVICEARRIVAL:
msgCount++;
pusbctl = UsbController::instance();
pusbctl->signalDeviceArrival();
break;
case DBT_DEVICEREMOVECOMPLETE:
msgCount++;
pusbctl = UsbController::instance();
pusbctl->signalDeviceRemoval();
break;
case DBT_DEVNODES_CHANGED:
msgCount++;
pusbctl = UsbController::instance();
pusbctl->signalDeviceAddedRemoved();
break;
default:
msgCount++;
break;
}
}
break;
default:
// Send all other messages on to the default windows handler.
lRet = DefWindowProc(__hWnd, message, wParam, lParam);
break;
}
return lRet;
}
BOOL DoRegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND __hWnd, HDEVNOTIFY *hDeviceNotify)
{
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
//NotificationFilter.dbcc_devicetype = DEVICE_NOTIFY_ALL_INTERFACE_CLASSES;
NotificationFilter.dbcc_classguid = InterfaceClassGuid;
*hDeviceNotify = RegisterDeviceNotification(
__hWnd, // events recipient
&NotificationFilter, // type of device
DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
);
if ( NULL == *hDeviceNotify )
{
return FALSE;
}
return TRUE;
}
1 ответ:
Если Вы читаете документацию MSDN, там написано:
Обнаружение вставки или удаления носителей
Windows отправляет всем окнам верхнего уровня наборсообщений по умолчанию WM_DEVICECHANGE, когда новые устройства или носители (такие как CD или DVD) добавляются и становятся доступными, а также когда существующие устройства или носители удаляются. Вам не нужно регистрироваться, чтобы получать эти сообщенияпо умолчанию . смотрите раздел Примечания в RegisterDeviceNotification для сведения о том, какие сообщения отправляются по умолчанию.
RegisterDeviceNotification функция
Любое приложение с окном верхнего уровня может получать основные уведомления, обрабатывая сообщение WM_DEVICECHANGE. Приложения могут использовать функцию RegisterDeviceNotification для регистрации для получения уведомлений устройства .
...
События DBT_DEVICEARRIVAL и DBT_DEVICEREMOVECOMPLETE являются автоматически вещание на все окна верхнего уровня для портовых устройств . Поэтому нет необходимости вызывать RegisterDeviceNotification для портов , и функция завершается ошибкой, если членом dbch_devicetype является DBT_DEVTYP_PORT.DBT_DEVTYP_PORT
0x00000003Порт устройства (последовательный или параллельный) . Эта структура является структурой DEV_BROADCAST_PORT.
USB-устройство не является последовательным / параллельным портом. Это интерфейс устройства (
DBT_DEVTYP_DEVICEINTERFACE). И ещеDBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETEне отправляются для устройствDBT_DEVTYP_DEVICEINTERFACEпо умолчанию . Если вы хотите их, вы должны использоватьRegisterDeviceNotification(), чтобы запросить их.Похоже, что ваш код основан на следующем примере MSDN:
Регистрация для уведомления устройства
В этом коде
WceusbshGUIDопределяется как{25dbce51-6c8f-4a72-8a6d-b54c2b4fc835}, который комментируется как guid класса для драйверов PnP последовательного хоста USB. По данным этого сайта MSDN страница:Системные классы настройки устройств, доступные поставщикам
Что guid-это класс guid дляустройств Windows CE USB ActiveSync (что более согласуется с префиксом
Wceusb..., используемым в коде). Также на этой же странице находится{88BAE032-5A81-49f0-BC3D-A4FF138216D6}для USB-устройства (все USB-устройства, которые не принадлежат к другому классу).Следующая статья CodeProject:
Обнаружение установки оборудования и / или Удаление
Упоминает
Поэтому, когда вы вызываете{a5dcbf10-6530-11d2-901f-00c04fb951ed}для USB Raw Device. Тот же guid задокументирован на MSDN какGUID_DEVINTERFACE_USB_DEVICE(именование которых, вероятно, восходит к временам до XP, когда имена GUID классов и GUID интерфейсов не были хорошо разделены).RegisterDeviceNotification()с определенным guid класса, убедитесь, что это правильный guid класса, так как вы собираетесь получить события устройства только для этого определенного типа устройства. Вполне вероятно, что ваше USB-устройство использует другой guid класса, чем тот, который вы регистрируете, и именно поэтому вы не получаете ожидаемых событий устройства.Если вы хотите обнаружить любое USB-устройство независимо от его класса guid (а существует несколько определенных классов GUID USB), вы можете использовать флаг
DEVICE_NOTIFY_ALL_INTERFACE_CLASSESпри вызовеRegisterDeviceNotification(), тогда класс guid будет проигнорирован. В сообщенияхDBT_DEVICEARRIVALиDBT_DEVICEREMOVECOMPLETE(предполагая, что вы можете получить их сейчас), сообщенныеdbcc_classguidбудут назовите вам фактический guid класса, и сообщениеdbcc_nameначнется с префикса\\?\USB:.И последнее - вы будете получать сообщения
DBT_DEVICE...только в том случае, если USB-устройство вставлено/удалено, когда ваше приложение уже запущено. Чтобы определить, подключено ли USB-устройство уже при запуске приложения, необходимо использовать функции SetupAPI (SetupDiGetClassDevs(),SetupDiEnumDeviceInterfaces(),SetupDiGetDeviceInterfaceDetail(), и т.д.) для перечисления доступных устройств.
Comments