Windows 透過 WM_DEVICECHANGE 視窗訊息通知應用程式裝置到達/移除。wParam 為事件類型,lParam 指向 DEV_BROADCAST_HDR 結構,可轉型為 DEV_BROADCAST_VOLUME 判斷磁碟機類型。
BOOL CMyDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)dwData;
if (!pHdr) return TRUE;
switch (nEventType) {
case DBT_DEVICEARRIVAL: // 裝置到達
if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
PDEV_BROADCAST_VOLUME pVol = (PDEV_BROADCAST_VOLUME)pHdr;
// pVol->dbcv_unitmask 位圖:bit 0=A:, bit 1=B: ...
for (int i = 0; i < 26; ++i) {
if (pVol->dbcv_unitmask & (1 << i)) {
TCHAR szDrive[4] = { _T('A') + i, _T(':'), _T('\\'), 0 };
if (GetDriveType(szDrive) == DRIVE_REMOVABLE) {
// 偵測到 USB 磁碟/隨身碟插入
OnUsbInserted(szDrive);
}
}
}
}
break;
case DBT_DEVICEREMOVECOMPLETE: // 裝置移除完成
if (pHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
PDEV_BROADCAST_VOLUME pVol = (PDEV_BROADCAST_VOLUME)pHdr;
// 同理解析 unitmask,判斷移除的磁碟機
OnUsbRemoved(pVol->dbcv_unitmask);
}
break;
case DBT_DEVNODES_CHANGED: // 裝置拓撲變更 (通用)
RefreshDeviceList();
break;
}
return TRUE;
}
typedef struct _DEV_BROADCAST_VOLUME {
DWORD dbcv_size; // 結構大小
DWORD dbcv_devicetype; // DBT_DEVTYP_VOLUME (0x00000002)
DWORD dbcv_reserved;
DWORD dbcv_unitmask; // 位圖,對應磁碟機代號
WORD dbcv_flags; // DBTF_MEDIA (媒體變更) / DBTF_NET (網路磁碟)
} DEV_BROADCAST_VOLUME, *PDEV_BROADCAST_VOLUME;
若需偵測非磁碟類 USB 裝置 (如印表機、HID),需呼叫 RegisterDeviceNotification 註冊 GUID 介面類別:
GUID InterfaceClassGuid = GUID_DEVINTERFACE_USB_DEVICE; // 或特定類別 GUID
DEV_BROADCAST_DEVICEINTERFACE filter = {0};
filter.dbcc_size = sizeof(filter);
filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
filter.dbcc_classguid = InterfaceClassGuid;
HDEVNOTIFY hNotify = RegisterDeviceNotification(m_hWnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
// 視窗銷毀時 UnregisterDeviceNotification(hNotify);
RegisterDeviceNotification 搭配 SERVICE_CONTROL_DEVICEEVENT。WM_DEVICECHANGE,但部分裝置資訊受限。GetLogicalDrives 比對前後差異。