青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 224  文章 - 41  trackbacks - 0
<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

享受編程

常用鏈接

留言簿(11)

隨筆分類(159)

隨筆檔案(224)

文章分類(2)

文章檔案(4)

經(jīng)典c++博客

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

原文地址:http://www.cnblogs.com/SunYu/archive/2010/04/29/1723977.html
codeproject:http://www.codeproject.com/KB/system/HwDetect.aspx

 

簡介

現(xiàn)在對于IT的安全來說,熱插撥設備是個很大的威脅。在這篇文章中,我將試著開發(fā)一個用戶應用程序來檢測本機系統(tǒng)上的設備改變。例如:插入一個USB設備、Ipod、USB無線網(wǎng)卡等等。這個程序同樣也可以停用任何支持插拔的設備。在文章的后面,我會簡述一下程序的工作原理和它的局限性。

怎么來檢測硬件設備的改變?

事實上,Windows操作系統(tǒng)會對上層程序發(fā)送WM_DEVICECHANGE消息來通知設備的改變。我們所要作的僅僅是添加一個句柄來處理這個事件。

Collapse

BEGIN_MESSAGE_MAP(CHWDetectDlg, CDialog)
    // ... other handlers
    ON_MESSAGE(WM_DEVICECHANGE, OnMyDeviceChange)
END_MESSAGE_MAP()
 
LRESULT CHWDetectDlg::OnMyDeviceChange(WPARAM wParam, LPARAM lParam)
{
    // for more information, see MSDN help of WM_DEVICECHANGE
    // this part should not be very difficult to understand
    if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam ) {
        PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
        switch( pHdr->dbch_devicetype ) {
            case DBT_DEVTYP_DEVICEINTERFACE:
                PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
                // do something...
                break;
 
            case DBT_DEVTYP_HANDLE:
                PDEV_BROADCAST_HANDLE pDevHnd = (PDEV_BROADCAST_HANDLE)pHdr;
                // do something...
                break;
 
            case DBT_DEVTYP_OEM:
                PDEV_BROADCAST_OEM pDevOem = (PDEV_BROADCAST_OEM)pHdr;
                // do something...
                break;
 
            case DBT_DEVTYP_PORT:
                PDEV_BROADCAST_PORT pDevPort = (PDEV_BROADCAST_PORT)pHdr;
                // do something...
                break;
 
            case DBT_DEVTYP_VOLUME:
                PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;
                // do something...
                break;
        }
    }
    return 0;
}

然而默認情況下,Windows操作系統(tǒng)發(fā)送WM_DEVICECHANGE有些限制:

1 只有頂層窗體的程序才能收到這個消息

2 僅僅串口、磁盤發(fā)生改變,才對每個程序廣播這個消息

的確不錯,至少你可以知道移動U盤、移動硬盤、光盤被安裝或彈出了,通過DEV_BROADCAST_VOLUME.dbcv_unitmask你也可以獲得其對應的盤符。但實際上,你不知道底層處理的是哪個物理設備實際上被安裝到了系統(tǒng)中。

API:RegisterDeviceNotification()

所以,你不得不調(diào)用RegisterDeviceNotification()API來注冊其他類型的設備改變,或是你的程序僅僅是一個服務程序、沒有頂層窗體的程序。例如:如下的例子是用來注冊一個設備類型的接口的:

Collapse

1.  DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
2.  ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
3.  NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
4.  NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
5.  // assume we want to be notified with USBSTOR
6.  // to get notified with all interface on XP or above
7.  // ORed 3rd param with DEVICE_NOTIFY_ALL_INTERFACE_CLASSES and dbcc_classguid will be ignored
8.  NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USBSTOR;
9.  HDEVNOTIFY hDevNotify = RegisterDeviceNotification(this->GetSafeHwnd(),
        amp;NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
10. if( !hDevNotify ) {
11.     // error handling...
12.     return FALSE;
13. }

請注意第8行,NotificationFilter.dbcc_classguid關注的就是你關心的一類設備。

參考這個blog: Doron Holan's blog

一個支持即插即用的設備,有2個不同的GUID相關,一個設備接口GUID, 一個是設備類GUID

設備類GUID:定義了廣泛意義上一類設備的GUID,如果你打開設備管理器[我的電腦右鍵—>設備管理器],默認的是按照“類型”排列的,每一個“類型”就是一個設備類,同時每一個設備類有一個唯一的ID就是設備類GUID。設備GUID定義了此類設備的圖標、默認的安全設置、安裝屬性(例如用戶不能手動安裝這類設備,而必須通過PNP來遍歷),以及其他的設置信息。設備類GUID沒有定義對應的I/O接口(請參考術語表),而更像是設備的分組。我認為一個比較好的例子是端口類。串口COM和并口LPT 都是端口類的一部分,但其各有各的I/O接口,而且彼此互不兼容.一個設備僅僅屬于一個設備類。我們可以通過設備驅(qū)動的INF文件的開頭來查看該設備的設備類GUID。

設備接口GUID:定義了相互關聯(lián)I/O接口的GUID,每一個接口GUID的具體實例都支持基本的I/O設置。設備接口GUID也是對應的驅(qū)動程序基于PNP狀態(tài)來注冊、啟用、禁用設備。如果需要,一個設備甚至可以注冊多個同樣GUID的實例(假使每個都有相同的名字)[注:在實際的程序中,多次插拔USB口,確實會驅(qū)出相同的串口,例如port12,port12,port12…],盡管在現(xiàn)實世界中完全不需要這樣。一個簡單的I/O關聯(lián)接口是鍵盤設備,每個鍵盤設備的接口GUID必須相同。

可以通過如下的注冊表路徑來查看當前設備類GUID 設備接口GUID

  • \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class
  • \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses

常用設備的接口GUID如下:

設備接口名稱

GUID

USB Raw Device/USB設備

{a5dcbf10-6530-11d2-901f-00c04fb951ed}

Disk Device/磁盤設備

{53f56307-b6bf-11d0-94f2-00a0c91efb8b}

Network Card/網(wǎng)卡

{ad498944-762f-11d0-8dcb-00c04fc3358c}

Human Interface Device (HID)/人機界面設備

{4d1e55b2-f16f-11cf-88cb-001111000030}

Palm/手持設備

{784126bf-4190-11d4-b5c2-00c04f687a67}

DEV_BROADCAST_DEVICEINTERFACE的解碼

如下是修改處理捕獲對應事件的函數(shù):

Collapse

LRESULT CHWDetectDlg::OnMyDeviceChange(WPARAM wParam, LPARAM lParam)
{
    ....
    ....
    if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam )
    {
        PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
        switch( pHdr->dbch_devicetype )
        {
            case DBT_DEVTYP_DEVICEINTERFACE:
                PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
                UpdateDevice(pDevInf, wParam);
                break;
    ....
    ....
}

從MSDN中,我們知道

Collapse

typedef struct _DEV_BROADCAST_DEVICEINTERFACE {
    DWORD dbcc_size;
    DWORD dbcc_devicetype;
    DWORD dbcc_reserved;
    GUID dbcc_classguid;
    TCHAR dbcc_name[1];
} DEV_BROADCAST_DEVICEINTERFACE *PDEV_BROADCAST_DEVICEINTERFACE;

我們似乎可以通過dbcc_name知道那個設備安裝到了當前系統(tǒng)。J,答案是不對,dbcc_name僅僅是操作系統(tǒng)內(nèi)部使用來做為ID的,其實不易讀的,例如下面的這個dbcc_name:

 

\\?\USB#Vid_04e8&Pid_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed}

  • \\?\USB: USB 意思是這是一個USB設備類
  • Vid_04e8&Pid_053b: Vid/Pid 是一個廠商ID和產(chǎn)品ID(但這是由設備類指定的,USB設備類使用VID/PID,不同的設備類使用不同的命名約定)
  • 002F9A9828E0F06: 不清楚是怎么生成的,是唯一設備ID
  • {a5dcbf10-6530-11d2-901f-00c04fb951ed}:設備接口類GUID

現(xiàn)在,我們來解出設備描述信息或是設備別名,有2種辦法:

1 直接讀注冊表, \\HKLM\SYSTEM\CurrentControlSet\Enum\USB\Vid_04e8&Pid_503b\0002F9A9828E0F06

2 使用 SetupDiXxx 系列API

API:SetupDiXxx()

Windows定義了一組API,讓用戶通過編程的辦法來獲取對應的硬件設備信息。例如,我們可以通過dbcc_name來獲得設備描述信息或是設備別名。下面是這個辦法都具體步驟:

1 首先通過SetupDiGetClassDevs()來獲得設備信息集 HDEVINFO,這個操作等同于是一個獲取目錄句柄的過程。

2 接著使用SetupDiEnumDeviceInfo()來遍歷出這個設備信息集內(nèi)的所有設備,這個操作等同于把目錄列表的過程。對于每個遍歷出的,我們可以獲得SP_DEVINFO_DATA,這個等同于是文件句柄。

3 在上面的枚舉過程中,使用SetupDiGetDeviceInstanceId()來讀取每個設備的實例ID,這個操作等同于是讀文件的屬性,一個設備的實例ID類似這個:”USB\Vid_04e8&Pid_503b\0002F9A9828E0F06”,和dbcc_name非常像。

4 如果設備的實例ID等同于dbcc_name,則通過SetupDiGetDeviceRegistryProperty()來獲取設備描述信息或是設備別名信息。

程序如下:

Collapse

void CHWDetectDlg::UpdateDevice(PDEV_BROADCAST_DEVICEINTERFACE pDevInf, WPARAM wParam)
{
    // dbcc_name:
    // \\?\USB#Vid_04e8&Pid_503b#0002F9A9828E0F06#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
    // convert to
    // USB\Vid_04e8&Pid_503b\0002F9A9828E0F06
    ASSERT(lstrlen(pDevInf->dbcc_name) > 4);
    CString szDevId = pDevInf->dbcc_name+4;
    int idx = szDevId.ReverseFind(_T('#'));
    ASSERT( -1 != idx );
    szDevId.Truncate(idx);
    szDevId.Replace(_T('#'), _T('\\'));
    szDevId.MakeUpper();
 
    CString szClass;
    idx = szDevId.Find(_T('\\'));
    ASSERT(-1 != idx );
    szClass = szDevId.Left(idx);
 
    // if we are adding device, we only need present devices
    // otherwise, we need all devices
    DWORD dwFlag = DBT_DEVICEARRIVAL != wParam
        ? DIGCF_ALLCLASSES : (DIGCF_ALLCLASSES | DIGCF_PRESENT);
    HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, szClass, NULL, dwFlag);
    if( INVALID_HANDLE_VALUE == hDevInfo )
    {
        AfxMessageBox(CString("SetupDiGetClassDevs(): ")
            + _com_error(GetLastError()).ErrorMessage(), MB_ICONEXCLAMATION);
        return;
    }
 
    SP_DEVINFO_DATA* pspDevInfoData =
        (SP_DEVINFO_DATA*)HeapAlloc(GetProcessHeap(), 0, sizeof(SP_DEVINFO_DATA));
    pspDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
    for(int i=0; SetupDiEnumDeviceInfo(hDevInfo,i,pspDevInfoData); i++)
    {
        DWORD DataT ;
        DWORD nSize=0 ;
        TCHAR buf[MAX_PATH];
 
        if ( !SetupDiGetDeviceInstanceId(hDevInfo, pspDevInfoData, buf, sizeof(buf), &nSize) )
        {
            AfxMessageBox(CString("SetupDiGetDeviceInstanceId(): ")
                + _com_error(GetLastError()).ErrorMessage(), MB_ICONEXCLAMATION);
            break;
        }
 
        if ( szDevId == buf )
        {
            // device found
            if ( SetupDiGetDeviceRegistryProperty(hDevInfo, pspDevInfoData,
                SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize) ) {
                // do nothing
            } else if ( SetupDiGetDeviceRegistryProperty(hDevInfo, pspDevInfoData,
                SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize) ) {
                // do nothing
            } else {
                lstrcpy(buf, _T("Unknown"));
            }
            // update UI
            // .....
            // .....
            break;
        }
    }
 
    if ( pspDevInfoData ) HeapFree(GetProcessHeap(), 0, pspDevInfoData);
    SetupDiDestroyDeviceInfoList(hDevInfo);
}

禁用設備

假使你有一個正確的HDEVINFO和SP_DEVINFO_DATA(實際上,我們保持dbcc_name座位樹節(jié)點的tag,當右鍵單擊某一個節(jié)點的時候,可以通過調(diào)用SetupDiGetClassDevs和SetupDiEnumDeviceInfo來獲得所需東西),按照如下的步驟即可禁用一個設備:

1 給SP_PROPCHANGE_PARAMS結構體賦上正確的值

2 把上面賦完值的SP_PROPCHANGE_PARAMS作為參數(shù)傳入到SetupDiSetClassInstallParams()

3 調(diào)用SetupDiCallClassInstaller(),傳遞參數(shù)DIF_PROPEFRTYCHANGE

實際上,DIF也是按位做與運算后兼容的,你也可以去傳遞不同的DIF參數(shù)來調(diào)用SetupDiSetClassInstallParams()。 更多信息,請參考MSDN”Handling DIF Codes”

Collapse

SP_PROPCHANGE_PARAMS spPropChangeParams ;
spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE ;
spPropChangeParams.Scope = DICS_FLAG_GLOBAL ;
spPropChangeParams.HwProfile = 0; // current hardware profile
spPropChangeParams.StateChange = DICS_DISABLE
 
if( !SetupDiSetClassInstallParams(hDevInfo, &spDevInfoData,
    // note we pass spPropChangeParams as SP_CLASSINSTALL_HEADER
    // but set the size as sizeof(SP_PROPCHANGE_PARAMS)
    (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(SP_PROPCHANGE_PARAMS)) )
{
    // handle error
}
else if(!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, &spDevInfoData))
{
    // handle error
}
else
{
    // ok, show disable success dialog
    // note, after that, the OS will post DBT_DEVICEREMOVECOMPLETE for the disabled device
}

附錄:

我使用這個程序,已經(jīng)多次測試了USB的無線網(wǎng)卡的,插入、拔出測試。

局限性:

1 明顯的,必須先運行該程序,才能檢測硬件設備。例如:設備在操作系統(tǒng)啟動前就已經(jīng)連接,或者在這個程序運行前的連接都不會被檢測。但這個問題,可以通過保存當前系統(tǒng)配置到遠程計算機上,等啟動完這個程序后再堅持不同的配置來解決

2 我們可以禁用設備,換而言之這也是我們所有能做到。我們不能訪問設備底層控制。 我認為可以通過重新用基于內(nèi)核的過濾驅(qū)動來實現(xiàn),則可以解決這個問題。

posted on 2010-09-13 21:27 漂漂 閱讀(11418) 評論(0)  編輯 收藏 引用 所屬分類: 深入vc++c#開發(fā)
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            免费久久99精品国产自在现线| 久久久噜噜噜久久中文字幕色伊伊| 欧美一区亚洲一区| 日韩一级精品视频在线观看| 亚洲欧洲一级| 久久躁日日躁aaaaxxxx| 麻豆成人小视频| 欧美高清在线视频| 99日韩精品| 欧美视频二区36p| 欧美中文字幕视频| 久久婷婷色综合| 亚洲观看高清完整版在线观看| 亚洲国产精品t66y| 一本色道久久综合一区| 性欧美videos另类喷潮| 老鸭窝亚洲一区二区三区| 欧美日韩国产一级片| 国产人久久人人人人爽| 亚洲国产精品va在线看黑人| 看片网站欧美日韩| 久久蜜臀精品av| 久久久久久久久岛国免费| 老司机免费视频一区二区三区| 亚洲国产美女久久久久| 亚洲一级高清| 免费在线观看成人av| 国产精品免费电影| 亚洲国产精品久久久久秋霞影院 | 一区二区三区蜜桃网| 一区二区三区视频在线播放| 欧美在线亚洲在线| 亚洲日本理论电影| 欧美专区在线观看| 欧美精品自拍偷拍动漫精品| 国产一区欧美日韩| 一本一道久久综合狠狠老精东影业| 久久精品欧洲| 亚洲欧美国产高清| 亚洲精品一区在线观看| 性感少妇一区| 欧美日韩综合一区| 亚洲国产精品悠悠久久琪琪 | 欧美午夜a级限制福利片| 狠狠色丁香婷婷综合| 亚洲在线视频观看| 亚洲日本成人在线观看| 久久久综合网| 极品尤物久久久av免费看| 亚洲男女自偷自拍| 亚洲精品影院| 欧美精品在线观看| 亚洲狼人精品一区二区三区| 欧美国产精品日韩| 六月婷婷一区| 亚洲国产精品毛片| 欧美电影免费观看网站| 欧美一区二粉嫩精品国产一线天| 欧美日韩另类字幕中文| 亚洲美女av黄| 亚洲精品一级| 国产精品成人v| 亚洲一区在线观看视频| 在线亚洲欧美| 国产精品无码永久免费888| 一区二区三区.www| 亚洲精品国产视频| 欧美午夜电影在线| 欧美亚洲在线视频| 亚洲第一成人在线| 久久永久免费| 亚洲激情二区| 国产一区二区你懂的| 久久精品亚洲一区二区三区浴池| 亚洲欧美激情视频在线观看一区二区三区 | 日韩午夜在线播放| 在线视频免费在线观看一区二区| 国产精品毛片a∨一区二区三区|国| 蜜臀av一级做a爰片久久| 国产精品一区一区| 日韩视频亚洲视频| 国产日本亚洲高清| 亚洲色图综合久久| 欧美一区二区视频在线观看| 欧美日韩视频在线一区二区| 亚洲欧美日本精品| 欧美久色视频| 亚洲婷婷综合色高清在线 | 国产一区高清视频| 午夜久久福利| 一区二区三区欧美激情| 欧美xxx成人| 亚洲日本理论电影| 99ri日韩精品视频| 亚洲欧美视频一区| 99国产精品私拍| 欧美日韩国产一区二区| 欧美激情一区二区在线 | 欧美日韩无遮挡| 久久久久国产成人精品亚洲午夜| 免费试看一区| 欧美96在线丨欧| 亚洲精品三级| 免费成人av资源网| 亚洲精品少妇网址| 欧美在线电影| 国产一区欧美| 国产精品成人免费| 亚洲综合99| 免费久久精品视频| 久久精品91久久香蕉加勒比| 一级日韩一区在线观看| 亚洲国产成人精品视频| 免费观看一级特黄欧美大片| 欧美一区二区在线免费观看| 一色屋精品亚洲香蕉网站| 久久久久久久一区| 久久se精品一区二区| 欧美大香线蕉线伊人久久国产精品| 国产欧美精品日韩| 欧美国产日韩精品| 亚洲欧美日韩一区二区| 亚洲国产精品久久久久秋霞蜜臀| 久久精品视频亚洲| 欧美大秀在线观看| 亚洲福利在线视频| 香蕉免费一区二区三区在线观看| 国内精品视频久久| 激情视频一区二区| 国产精品海角社区在线观看| 国产在线视频不卡二| 国产精品久久久久久久久婷婷 | 亚洲美女黄网| 一区二区三区鲁丝不卡| 一区二区三区欧美亚洲| 日韩一级精品视频在线观看| 亚洲免费观看视频| 亚洲图片欧美一区| 亚洲欧美韩国| 久久精品盗摄| 亚洲第一精品在线| 99ri日韩精品视频| 亚洲一区免费观看| 久久精品夜夜夜夜久久| 欧美激情中文不卡| 亚洲视频一区二区免费在线观看| 亚洲区一区二区三区| 亚洲欧美日韩爽爽影院| 欧美精品日日鲁夜夜添| 国内视频精品| 在线一区观看| 亚洲国产福利在线| 亚洲欧美国产一区二区三区| 欧美久久久久久蜜桃| 亚洲午夜未删减在线观看| 久久麻豆一区二区| 亚洲成色最大综合在线| 亚洲激情另类| 亚洲精品一级| 欧美精品1区2区3区| 狠狠色综合一区二区| 亚洲福利视频一区| 亚洲黄色小视频| 欧美视频久久| 亚洲精品女av网站| 久久一区二区三区四区| 欧美不卡视频一区发布| 欧美日韩免费在线观看| 99精品国产在热久久下载| 亚洲黄一区二区三区| 欧美深夜福利| 亚洲一区在线播放| 亚洲免费视频在线观看| 国产精品网站在线| 久久亚洲欧美| 亚洲每日在线| 久久女同互慰一区二区三区| 一本大道久久a久久综合婷婷| 欧美国产精品劲爆| 欧美一二三视频| 欧美国产视频日韩| 欧美一区二区三区免费视| 欧美在线关看| 99热这里只有精品8| 亚洲欧美精品在线观看| 国产欧美精品在线| 亚洲国产导航| 欧美日韩不卡一区| 久久久噜噜噜久久| 免费试看一区| 久久国产精品72免费观看| 鲁大师影院一区二区三区| 日韩午夜av电影| 亚洲国产成人精品视频| 亚洲曰本av电影| 亚洲欧美日韩成人高清在线一区| 亚洲黄色在线看| 久久久久国产一区二区三区四区| 亚洲自拍偷拍麻豆| 欧美日韩123|