С расширением рынка переносных устройств и USB-накопителей становится актуальной задача по обработке их взаимодействия с компьютером. Сегодня разберем обработку подключения и отключения съемных накопителей, таких как Flash-диски, карты памяти и USB-диски. Начинаем с теории. При подключении или отключении съемного накопителя система посылает всем окнам (через глобальный хэндл HWND_BROADCAST) сообщение
WM_DEVICECHANGE. Но это сообщение всего лишь о самом факте изменения состояния съемного накопителя, а более подробные значения содержатся в параметрах lParam и wParam этого сообщения. В wParam приходит расшифровка произошедшего события: подключение, отключение, изменения состояния, отмена отключения и т.п. Нас пока интересует только два: DBT_DEVICEARRIVAL - подключение сменного накопителя и DBT_DEVICEREMOVECOMPLETE - извлечение накопителя. Основной обработчик событий приложения ничем не отличается от обычных обработчиков. Нам также понадобятся несколько констант, которые по умолчанию не определены в FASM:
DBT_DEVICEARRIVAL = 0x8000
DBT_DEVICEREMOVECOMPLETE = 0x8004
DBT_DEVTYP_VOLUME = 0x00000002
И, собственно, сам обработчик. Я оставил только нужные фрагменты кода:
Code (Assembler) : Убрать нумерацию
proc DialogProc hwnddlg,msg,wparam,lparam
push ebx esi edi
...
; Пришло сообщение об изменении состояния съемного накопителя
cmp [msg],WM_DEVICECHANGE
je update_usb
...
update_usb:
; Устройство подключено?
cmp [wparam],DBT_DEVICEARRIVAL
je usb_connected
; Устройство извлечено?
cmp [wparam],DBT_DEVICEREMOVECOMPLETE
je usb_disconnected
jmp processed
usb_connected:
; Обработка подключения устройства
...
jmp processed
usb_disconnected:
; Обработка отключения устройства
...
jmp processed
...
processed:
mov eax,1
finish:
pop edi esi ebx
ret
endp
Для полноты картины осталось узнать, какой именно диск был подключен или извлечен. В параметре lParam сообщения WM_DEVICECHANGE передается указатель на структуру, которая содержит подробную информацию о случившемся событии. FASM про нее тоже ничего не знает, поэтому придется и ее описать самостоятельно.
Структура состоит из двух частей: заголовка и информационной части. В заголовке содержится общая информация, а информационная часть может различаться в зависимости от типа устройства, на котором произошло событие. Для съемных дисков она будет следующая:
struct DEV_BROADCAST
; Заголовок структуры
dbch_size dd ?
dbch_devicetype dd ?
dbch_reserved dd ?
; Информационная часть структуры
dbcv_unitmask dd ?
dbcv_flags dd ?
ends
Поскольку сообщения могут приходить от разных устройств, а нас интересуют только съемные накопители, то в обработчики придется добавить фильтр. Поле заголовка dbch_devicetypeсодержит значение типа устройства, в нашем случае это должно быть DBT_DEVTYP_VOLUME, оно описано выше. Все остальные сообщения мы должны пропускать без обработки. Также имейте в виду, что некоторые устройства, например, флоппи-дисководы или CD-ROM могут вообще не инициировать никаких событий, и смену носителей в них отследить не получится.
Чтобы узнать букву диска, которую система присвоила съемному носителю, надо разобрать значение dbcv_unitmask из информационной части структуры. Это битовая маска, где каждый отдельный бит соответствует определенной букве: бит 0 соответствует диску A, бит 1 - диску B, бит 2 - диску C и так далее. Я нашел несколько вариантов преобразования такой маски в человеко-понятную букву, но решил сделать свой, обойдясь двумя ассемблерными командами:
; Получить букву диска из битовой маски (маска в регистре EAX)
bsr eax,eax
; В регистре AL буква диска
add al,'A'
Теперь у нас есть все данные для обработки подключения и отключения съемных накопителей. Вот некоторые варианты применения таких обработчиков: резервное сохранение важных данных при неожиданном отключении накопителя, антивирусный мониторинг подключаемых USB-дисков, незаметное фоновое копирование данных с флешек или запись на них какой-либо информации, и многое-многое другое. Все зависит только от вашей фантазии и порядочности.
В приложении пример программы, записывающей в свой лог все сообщения о подключении и отключении съемных носителей с указанием букв дисков.