VC操作光驅

目前有許多的商業軟件特別是一些音頻、視頻播放軟件中都帶有自動監測光驅的彈出和送入的狀態,然後進行自動播放的功能。本文介紹的小軟件演示了一種自動識 別光驅彈出和送入狀態的能力,並且可以判斷出當前的光驅中是否有Windows系統可識別的CDROM碟片。程序實現過程中利用了Windows的 WM_DEVICECHANGE消息和Windows系統廣播機制來達到自動監測光驅狀態改變的目的。

一、實現原理

Windows 系統通過GDI(圖形設備接口)將系統的硬件和用戶可以操作的編程接口相分離,以保證系統的穩定型和安全性。當某一個設備的硬件配置發生變化時, Windows發送廣播消息WM_DEVICECHANGE給相關的應用和設備驅動程序,此時在應用程序中可以截獲該消息並分析其中的消息參數,先分辨當 前的消息內容,然後調用不同的事件處理程序。本文中主要考慮的是光驅的彈出和送入事件,因此程序設計時只需對邏輯驅動器進行掃描,判斷是哪個驅動器號發生 變化即可。一般的外設(包括軟、硬盤驅動器、光驅等)在Windows系統中按照邏輯上的驅動器名稱進行管理,這樣就屏蔽了用戶和計算機硬件直接打交道。 Windows中用掩碼數字0代表驅動器“A”,1代表驅動器“B”,依此類推。其中每個邏輯驅動器又有0和1兩種狀態變化,如果驅動器一直未發生變化, 則此值爲0,否則置爲1,一個邏輯驅動器狀態可以響應多種事件,如打開、關閉、新添加、刪除等事件,甚至可以響應用戶自定義的事件。

本文中的程序主要是監測光驅的彈出和送入的狀態改變,當應用程序啓動後,彈出一個對話框,說明正在等待光驅事件的發生,此時如果將光驅彈出,應用程序會提示此時光盤驅動器已經彈出,在送入光驅之後,並且光驅中有CDROM碟片時,應用會提示光驅已經就緒。

二、程序實現

從Visual C++的IDE中的File菜單中選擇New對話框,在Project屬性頁中選擇Win32 Application,建立一個空的Win32應用程序,將StdAfx.h和StdAfx.cpp包含進來。建立一個新的對話框資源,在對話框上寫上 一句靜態文本,“正在等待光驅事件”。下面實現監測光驅狀態變化的主程序,在主程序cdchange.cpp中實現了三個函數。

第一個函 數是chFirstDriveFromMask(ULONG unitmask),該函數的作用是將響應WM_DEVICECHANGE消息事件的內容(即驅動器掩碼)作爲輸入,和系統定義的掩碼相比較,從而返回發 生變化事件的驅動器的邏輯名稱,如“E盤”、“F盤”等。函數的源代碼如下:

char chFirstDriveFromMask (ULONG unitmask)

{

char i;

for (i = 0; i < 26; ++i) //假設不會超過26個邏輯驅動器

{

if (unitmask & 0x1) //看該驅動器的狀態是否發生了變化

break;

unitmask = unitmask >> 1;

}

return (i + 'A');

}

第 二個函數是關鍵,它是對話框的事件處理函數,同時也是用來截獲並處理Windows的WM_DEVICECHANGE事件。在該函數中首先聲明瞭一個 PDEV_BROADCAST_HDR類型的結構變量lpdb,該結構裏存儲了當WM_DEVICECHANGE消息產生時的設備事件信息,它的聲明在 VC98目錄下面的Include目錄中的dbt.h中。接着,進入事件和消息處理程序,當WM_DEVICECHANGE事件出現時,程序再判斷該消息 的附加消息參數以判斷CDROM的事件類型。當一個設備被插入並變得可用時,系統會發送廣播事件DBT_DEVICEARRIVAL,而當一個設備被除去 並變得不可用時,系統會發送廣播事件DBT_DEVICEREMOVECOMPLETE,根據這兩種消息可以判斷當前的光驅是否是開着的。處理完以上事件 之後,還要檢查一下光驅中是否由CDROM碟片,如有才彈出對話框表明光驅已經彈出或成功送入。同時爲了防止於其他的自動識別光驅狀態的應用產生衝突,本 例中將暫時禁止光驅的自動播放功能。函數的源代碼如下:

BOOL WINAPI DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

BOOL fRet = TRUE;// 返回值

//通過響應WM_DEVICECHANGE消息得到的設備事件信息結構

PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;

//對話框消息處理

switch (uMsg)

{

case WM_INITDIALOG:

fRet = TRUE;

break;

//對WM_DEVICECHANGE 消息進行處理

case WM_DEVICECHANGE:

char szMsg[80]; // 對話框中要表示的字符串

switch (wParam)

{

//當一個設備變得被插入並變得可用時,

//系統會發送廣播事件DBT_DEVICEARRIVAL

case DBT_DEVICEARRIVAL:

// 判斷CDROM碟片是否已經插入到光驅中

if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) {

PDEV_BROADCAST_VOLUME lpdbv=

(PDEV_BROADCAST_VOLUME) lpdb;

//判斷是否有CDROM碟片

if (lpdbv -> dbcv_flags & DBTF_MEDIA)

{

// 顯示消息,獲取光驅的邏輯驅動器號

wsprintf (szMsg, "驅動器%c: 已經可用/n",

chFirstDriveFromMask(lpdbv ->dbcv_unitmask));

MessageBox (hwnd, szMsg, "光驅自動監測", MB_OK |

MB_ICONINFORMATION);

}

}

break;

//當一個設備變得被移走並變得不可用時,

//系統會發送廣播事件DBT_ DEVICEREMOVECOMPLETE

case DBT_DEVICEREMOVECOMPLETE:

// 判斷CDROM碟片是否從光驅中移走

if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) {

PDEV_BROADCAST_VOLUME lpdbv =

(PDEV_BROADCAST_VOLUME)lpdb;

if (lpdbv -> dbcv_flags & DBTF_MEDIA)

{

//顯示消息,獲取光驅的邏輯驅動器號

wsprintf (szMsg, "驅動器%c: 已經彈出/n",

chFirstDriveFromMask(lpdbv ->dbcv_unitmask));

MessageBox (hwnd, szMsg, "光驅自動監測", MB_OK

| MB_ICONINFORMATION);

}

}

break;

}

//處理其他Windows消息

case WM_COMMAND:

int wmId, wmEvent;

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

switch (wmId)

{

case IDOK:

EndDialog(hwnd, 0);

break;

}

default:

fRet = FALSE;

break;

}

// 禁止光驅的AutoPlay功能

static UINT uMsgQueryCancelAutoPlay=

RegisterWindowMessage("QueryCancelAutoPlay");

if (uMsg==uMsgQueryCancelAutoPlay)

{

int n = MessageBox(hwnd, "你想禁止AutoPlay功能嗎?", NULL,

MB_YESNO | MB_ICONQUESTION);

// 1代表取消AutoPlay

// 0 t代表允許AutoPlay

SetDlgMsgResult(hwnd, uMsg, (n == IDYES) ? 1 : 0);

fRet = (n == IDYES) ? 1 : 0;

}

return(fRet);

}

第三個函數非常簡單,產生一個模式對話框。代碼如下:

int APIENTRY WinMain

(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

//從對話框模版資源中創建一個模式對話框

DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),

NULL, DlgProc);

return 0;

}

三、結束語

本 文介紹了一種自動判斷光驅狀態改變的方法。通過對該方法進行擴展,可以應用到任何外設的狀態改變監測應用中去。WM_DEVICECHANGE消息中提供 了豐富的事件類型,還可以支持用戶自定義的事件類型,通過處理這些事件可以編寫出對外部設備進行處理的更加複雜的應用。以上程序在Windows98和 Visual C++ 6.0環境下編譯通過。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章