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;
}
717   1  

1 ответ:

Если Вы читаете документацию MSDN, там написано:

Обнаружение вставки или удаления носителей

Windows отправляет всем окнам верхнего уровня наборсообщений по умолчанию WM_DEVICECHANGE, когда новые устройства или носители (такие как CD или DVD) добавляются и становятся доступными, а также когда существующие устройства или носители удаляются. Вам не нужно регистрироваться, чтобы получать эти сообщенияпо умолчанию . смотрите раздел Примечания в RegisterDeviceNotification для сведения о том, какие сообщения отправляются по умолчанию.

RegisterDeviceNotification функция

Любое приложение с окном верхнего уровня может получать основные уведомления, обрабатывая сообщение WM_DEVICECHANGE. Приложения могут использовать функцию RegisterDeviceNotification для регистрации для получения уведомлений устройства .
...
События DBT_DEVICEARRIVAL и DBT_DEVICEREMOVECOMPLETE являются автоматически вещание на все окна верхнего уровня для портовых устройств . Поэтому нет необходимости вызывать RegisterDeviceNotification для портов , и функция завершается ошибкой, если членом dbch_devicetype является DBT_DEVTYP_PORT.

DEV_BROADCAST_HDR структура

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

    Ничего не найдено.