Отслеживание подключения/отключения устройств
Добавлено: 22 фев 2008, 14:02
Как можно отследить подключение/отключение устройств (Flash, дисов в CD/DVD приводах и т.д.) ?
Почитав всякого, я написал описанный ниже способ. Но там возникла ситуация сродни: Картина Репина приплыли - 3 дня гребли, а трос отвязать забыли. У меня возник вопрос с GUID (смотри ниже).
Так же не хочется использовать способы в которых надо рыться в реестре, отслеживания по таймеру и т.д.
Кстати, я часто видел типа "ответы" по данной тематике, но в них почему-то дальше фразы о том, что надо использовать сообщение WM_DEVICECHANGE тема не развивается... :?
Вот один из возможных способ ( но может есть другие? ) :
Когда происходят изменения в устройствах (например, подключение/отключение Flash, дисов в CD/DVD приводах и т.д.) система рассылает всем открытым в данный момент приложениям сообщение WM_DEVICECHANGE. Сейчас интересует случай когда происходит подключение/отключение Flash, дисов в CD/DVD приводах.
Чтобы приложение основанное на MFC могло отловить и отроботать данное сообщение в карте сообщений необходимо написать следующее:
Из значений которые может принимать wParam для интересующего нас случая важно следующее:
DBT_DEVICEARRIVAL – подключили новое устройство
DBT_DEVICEREMOVECOMPLETE – устройство было отключено
Как я понял lParam является указателем на структуру, которая содержит в себе информацию о произошедших изменениях с устройствами.
Функция OnDeviceChange реализуется следующим образом:
Возможность использовать сообщение DBT_DEVNODES_CHANGED не подходит т.к. оно приходит по нескольку раз после подключения/отключения устройства.
И тут начинается самое интерестное:
По умолчанию сообщение WM_DEVICECHANGE, как уже было выше написано, рассылается всем открытым приложениям, но приложение не всегда будет принимать значения параметров wParam и lParam
(По-умолчанию они приходят top-level окнам). Т.о. если приложение оконное и не top-level или является сервисом, то для того что бы wParam и lParam содержали нужную информацию (DBT_...) необходимо зарегестрироваться в системе для получения сообщения. Это делается при помощи функции RegisterDeviceNotification:
hRecipient – хэндл окна или сервиса, который регистрируется в системе для получения сообщения.
Flags – определяет кто именно регистрируется сервис или приложение:
DEVICE_NOTIFY_WINDOW_HANDLE – hRecipient является хэндлом окна
DEVICE_NOTIFY_SERVICE_HANDLE – hRecipient является хэндлом сервиса
NotificationFilter – указатель на блок данных который содержит некоторую информацию об устройстве от которого принято сообщение (
) :
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
одно из полей этой структуры - dbcc_classguid - переменная типа GUID
Скажите, пожалуйста, что это (GUID) и как это получить в данном случае? И вообще, где правильно регистрироваться для получения сообщений?
Почитав всякого, я написал описанный ниже способ. Но там возникла ситуация сродни: Картина Репина приплыли - 3 дня гребли, а трос отвязать забыли. У меня возник вопрос с GUID (смотри ниже).
Так же не хочется использовать способы в которых надо рыться в реестре, отслеживания по таймеру и т.д.
Кстати, я часто видел типа "ответы" по данной тематике, но в них почему-то дальше фразы о том, что надо использовать сообщение WM_DEVICECHANGE тема не развивается... :?
Вот один из возможных способ ( но может есть другие? ) :
Когда происходят изменения в устройствах (например, подключение/отключение Flash, дисов в CD/DVD приводах и т.д.) система рассылает всем открытым в данный момент приложениям сообщение WM_DEVICECHANGE. Сейчас интересует случай когда происходит подключение/отключение Flash, дисов в CD/DVD приводах.
Чтобы приложение основанное на MFC могло отловить и отроботать данное сообщение в карте сообщений необходимо написать следующее:
Код: Выделить всё
ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange)
Из значений которые может принимать wParam для интересующего нас случая важно следующее:
DBT_DEVICEARRIVAL – подключили новое устройство
DBT_DEVICEREMOVECOMPLETE – устройство было отключено
Как я понял lParam является указателем на структуру, которая содержит в себе информацию о произошедших изменениях с устройствами.
Функция OnDeviceChange реализуется следующим образом:
Код: Выделить всё
#include <dbt.h>
LRESULT OnDeviceChange(WPARAM wParam, LPARAM lParam)
{
// следует обратить внимание на эту строку:
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
switch(wParam)
{
case DBT_DEVICEARRIVAL:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
MessageBox (NULL, _T(“Устройство подключено”), _T("WM_DEVICECHANGE"), MB_OK );
}
}
break;
case DBT_DEVICEREMOVECOMPLETE:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
MessageBox (NULL, _T(“Устройство отключено”), _T("WM_DEVICECHANGE"), MB_OK );
}
}
break;
}
}
И тут начинается самое интерестное:
По умолчанию сообщение WM_DEVICECHANGE, как уже было выше написано, рассылается всем открытым приложениям, но приложение не всегда будет принимать значения параметров wParam и lParam

Код: Выделить всё
HDEVNOTIFY RegisterDeviceNotification
(
HANDLE hRecipient,
LPVOID NotificationFilter,
DWORD Flags
);
hRecipient – хэндл окна или сервиса, который регистрируется в системе для получения сообщения.
Flags – определяет кто именно регистрируется сервис или приложение:
DEVICE_NOTIFY_WINDOW_HANDLE – hRecipient является хэндлом окна
DEVICE_NOTIFY_SERVICE_HANDLE – hRecipient является хэндлом сервиса
NotificationFilter – указатель на блок данных который содержит некоторую информацию об устройстве от которого принято сообщение (

DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
одно из полей этой структуры - dbcc_classguid - переменная типа GUID
Скажите, пожалуйста, что это (GUID) и как это получить в данном случае? И вообще, где правильно регистрироваться для получения сообщений?