Windows 系統透過 WM_DEVICECHANGE 廣播訊息通知應用程式硬體裝置狀態變更。本文詳細解析如何攔截該訊息,結合 DBT_DEVICEARRIVAL 與 DBT_DEVICEREMOVECOMPLETE 事件,實現光驅狀態的即時偵測與友善提示。
當光驅托盤彈出或送入時,系統會發送 WM_DEVICECHANGE,其 wParam 參數指示事件類型,lParam 指向 PDEV_BROADCAST_HDR 結構,包含裝置類型與邏輯磁碟機遮罩。透過解析遮罩即可定位具體磁碟機代號(如 E:、F:)。
char chFirstDriveFromMask(ULONG unitmask) {
char i;
for (i = 0; i < 26; ++i) {
if (unitmask & 0x1) break; // 找到變化位
unitmask >>= 1;
}
return (i + 'A'); // 轉為 'A'~'Z'
}
BOOL WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
static UINT uMsgQueryCancelAutoPlay = RegisterWindowMessage(_T("QueryCancelAutoPlay"));
switch (uMsg) {
case WM_DEVICECHANGE: {
char szMsg[80];
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) { // 有媒體(光碟)
wsprintf(szMsg, _T("驅動器 %c: 已經可用\n"),
chFirstDriveFromMask(lpdbv->dbcv_unitmask));
MessageBox(hwnd, szMsg, _T("光驅自動監測"), MB_OK | MB_ICONINFORMATION);
}
}
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) {
wsprintf(szMsg, _T("驅動器 %c: 已經彈出\n"),
chFirstDriveFromMask(lpdbv->dbcv_unitmask));
MessageBox(hwnd, szMsg, _T("光驅自動監測"), MB_OK | MB_ICONINFORMATION);
}
}
break;
}
break;
}
case uMsgQueryCancelAutoPlay: // 防衝突:暫停自動播放
if (MessageBox(hwnd, _T("你想禁止 AutoPlay 功能嗎?"), NULL,
MB_YESNO | MB_ICONQUESTION) == IDYES) {
SetDlgMsgResult(hwnd, uMsg, 1);
return 1;
}
break;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) {
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
return 0;
}
DBT_DEVTYP_VOLUME(邏輯磁碟區)DBTF_MEDIA 確認光碟實際存在QueryCancelAutoPlay 避免與系統自動播放衝突_T() 巨集支援雙字元集建置本方案適用於 Windows 2000/XP 及以上版本,為光碟燒錄軟體、多媒體播放器等需感知光驅狀態的應用提供了輕量級解決方案。