程式需即時偵測特定裝置(如網卡)被啟用或禁用,並在 UI 更新狀態。裝置管理器能即時反映,原理是接收 Windows 發送的裝置變更廣播訊息。
視窗程式透過處理 WM_DEVICECHANGE 訊息,配合 DBT_DEVICEARRIVAL(裝置到達/啟用)與 DBT_DEVICEREMOVECOMPLETE(裝置移除/禁用)事件類型實現。
// Header
afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData);
// CPP
BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()
BOOL CMyDlg::OnDeviceChange(UINT nEventType, DWORD_PTR dwData) {
PDEV_BROADCAST_HDR hdr = (PDEV_BROADCAST_HDR)dwData;
switch (nEventType) {
case DBT_DEVICEARRIVAL: // 裝置啟用/插入
if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
PDEV_BROADCAST_DEVICEINTERFACE dif = (PDEV_BROADCAST_DEVICEINTERFACE)hdr;
// dif->dbcc_name 包含裝置介面路徑,可解析 VID/PID
if (IsTargetDevice(dif->dbcc_name)) {
OnDeviceConnected(); // 自定義處理
}
}
break;
case DBT_DEVICEREMOVECOMPLETE: // 裝置禁用/拔出
if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
PDEV_BROADCAST_DEVICEINTERFACE dif = (PDEV_BROADCAST_DEVICEINTERFACE)hdr;
if (IsTargetDevice(dif->dbcc_name)) {
OnDeviceDisconnected();
}
}
break;
}
return TRUE;
}
bool IsTargetDevice(const wchar_t* devicePath) {
// 解析 devicePath 中的 VID_XXXX&PID_YYYY
// 或呼叫 SetupDiGetDeviceInterfaceDetail 取得詳細屬性比對
return wcsstr(devicePath, L"VID_1234&PID_5678") != nullptr;
}
RegisterDeviceNotification(m_hWnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE)。RegisterDeviceNotification(hService, &filter, DEVICE_NOTIFY_SERVICE_HANDLE) 並在 HandlerEx 處理 SERVICE_CONTROL_DEVICEEVENT。DWORD_PTR 確保指標大小正確。