程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> VC實現自動監測光驅狀態的改變

VC實現自動監測光驅狀態的改變

編輯:關於VC++

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;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved