1. 程式人生 > >關於windows熱插拔檢測的個人理解(使用Qt開發)

關於windows熱插拔檢測的個人理解(使用Qt開發)

在Qt中每一個視窗類(widget)都有一個處理windows訊息的函式,當windows出現熱插拔事件的時候,會向每個視窗傳送相應的WM_訊息,在Qt下,最終將調到natevieEvent函式;下面以QWidget為例:

virtual bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result);

一旦發生熱插拔事件,QWidgetnativeEvent函式將被呼叫,於是我們可以重新實現這個函式;

//Qt開發
virtual bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
    //在這裡做你想要的操作
    //其中eventType表明了此次訊息的型別,message儲存著具體是什麼資訊,result是個傳出變數;
    //eventType在windows作業系統下是"windows_generic_MSG"字串,可以檢視Qt的文件知道
    //message表明這個訊號附帶哪些資訊,在熱插拔事件中是WM_DEVICECHANGE型別,具體windows定義了哪些,可以檢視“Dbt.h”檔案
    
    //
    if(eventType == QByteArray("windows_generic_MSG"))
    {
        //MSG是winApi定義的結構體,具體定義如下:
        /*
         * typedef struct tagMSG {
         * HWND hwnd;
         * UINT message;   //訊息型別,熱插拔是WM_DEVICECHANGE
         * WPARAM wParam;  //對訊息的進一步描述
         * LPARAM lParam;  //指向一個結構體,結構中有好多訊息
         * DWORD time;     //產生時間
         * POINT pt;       //滑鼠座標
         * } MSG;
        */
        MSG *pMsg = reinterpret_cast<MSG*>(message);
        
        if(pMsg->message == WM_DEVICECHANGE)
        {
            switch(pMsg->wParam)
            {
            //裝置連上
            case DBT_DEVICEARRIVAL: doSomething(); break;
            //裝置斷開
            case DBT_DEVICEREMOVECOMPLETE: doSomething(); break;
            //其他的訊息可以檢視“Dbt.h”檔案
            }
        }

    }

    return false;
}

經過以上步驟,程式能夠捕捉到相應的訊息,但無法區分是由哪個裝置發出的;

然而很不巧的是,我也不懂,只知道一點,應該和LParam有關;

----------------------------------------------手動分割-----------------------------------------------------

下面的內容不作任何保障:

我查到的是:

第一步:先註冊訊息;

第二步:不知道!

先來說第一步:

首先你要知道有這麼一個 DEV_BOARDCAST_DEVICEINTERFACE結構體,從名稱上看,這就是一個和裝置廣播介面

//定義如下,別問為什麼多了"_A",
//其實還有一個"_DEV_BROADCAST_DEVICEINTERFACE_W"
//這個和應該是和平臺相關的
//所以不管,至少長得一樣
typedef struct _DEV_BROADCAST_DEVICEINTERFACE_A {
  DWORD dbcc_size;      //大小
  DWORD dbcc_devicetype;//裝置型別
  DWORD dbcc_reserved;  //保留字,忽略即可
  GUID  dbcc_classguid; //裝置類guid
  char  dbcc_name[1];   //名字,不知道怎麼用
} DEV_BROADCAST_DEVICEINTERFACE_A, *PDEV_BROADCAST_DEVICEINTERFACE_A;
//關於DEV_BOARDCAST_DEVICEINTERFACE的一個例子

DEV_BOARDCAST_DEVICEINTERFACE devInterface;

//為各個成員賦值
devInterface.dbcc_size       = sizeof(DEV_BOARDCAST_DEVICEINTERFACE);
devInterface.dbcc_devicetype = DBT_DEVTYPE_DEVICEINTERFACE;//其他的型別檢視“Dbt.h”檔案,
devInterface.dbcc_classguid  = GUID_DEVCLASS_USB;//其他型別檢視“devguid.h”檔案

其中的“dbcc_devicetype”的值將直接影響到“nativeEvent”中“MSG”結構體中的“meaasge”結構體中的“LParam”成員;

當,一個DEV_BOARDCAST_DEVICEINTERFACE結構體定義好了之後,就可以註冊了

//使用如下函式註冊
//

/*
 * 函式定義,別問為什麼是“W”
 * HDEVNOTIFY RegisterDeviceNotificationW(
 * HANDLE hRecipient,
 * LPVOID NotificationFilter,
 * DWORD  Flags  //檢視"winuser.h"
 * );
 */

//Qt開發環境下
RegisterDeviceNotification(HANDLE(this->winId()), &devInterface, DEVICE_NOTIFY_WINDOW_HANDLE);

至此註冊完畢,最後能知道是GUID_DEVCLASS_USB這種型別裝置產生的訊號(訊息);

那麼怎麼知道是哪個裝置產生的呢(前面說的是哪種),就要看“LParam”了;