小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

實戰(zhàn)DeviceIoControl 之五:列舉已安裝的存儲設(shè)備

 joysymbol 2007-03-14

Q 前幾次我們討論的都是設(shè)備名比較清楚的情況,有了設(shè)備名(路徑),就可以直接調(diào)用CreateFile打開設(shè)備,進行它所支持的I/O操作了。如果事先并不能確切知道設(shè)備名,如何去訪問設(shè)備呢?

A 訪問設(shè)備必須用設(shè)備句柄,而得到設(shè)備句柄必須知道設(shè)備路徑,這個套路以你我之力是改變不了的。每個設(shè)備都有它所屬類型的GUID,我們順著這個GUID就能獲得設(shè)備路徑。

GUID是同類或同種設(shè)備的全球唯一識別碼,它是一個128 bit(16字節(jié))的整形數(shù),真實面目為

typedef struct _GUID{    unsigned long  Data1;    unsigned short Data2;    unsigned short Data3;    unsigned char  Data4[8];} GUID, *PGUID;

例如,Disk類的GUID為“53f56307-b6bf-11d0-94f2-00a0c91efb8b”,在我們的程序里可以定義為

const GUID DiskClassGuid = {0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b)};

或者用一個宏來定義

DEFINE_GUID(DiskClassGuid, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);

通過GUID找出設(shè)備路徑,需要用到一組設(shè)備管理的API函數(shù)

SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetInterfaceDeviceDetail, SetupDiDestroyDeviceInfoList,

以及結(jié)構(gòu)SP_DEVICE_INTERFACE_DATA, SP_DEVICE_INTERFACE_DETAIL_DATA。

有關(guān)信息請查閱MSDN,這里就不詳細(xì)介紹了。

實現(xiàn)GUID到設(shè)備路徑的代碼如下:

// SetupDiGetInterfaceDeviceDetail所需要的輸出長度,定義足夠大#define INTERFACE_DETAIL_SIZE    (1024)  // 根據(jù)GUID獲得設(shè)備路徑// lpGuid: GUID指針// pszDevicePath: 設(shè)備路徑指針的指針// 返回: 成功得到的設(shè)備路徑個數(shù),可能不止1個int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath){    HDEVINFO hDevInfoSet;    SP_DEVICE_INTERFACE_DATA ifdata;    PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;    int nCount;    BOOL bResult;      // 取得一個該GUID相關(guān)的設(shè)備信息集句柄    hDevInfoSet = ::SetupDiGetClassDevs(lpGuid,     // class GUID         NULL,                    // 無關(guān)鍵字         NULL,                    // 不指定父窗口句柄         DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);    // 目前存在的設(shè)備      // 失敗...    if (hDevInfoSet == INVALID_HANDLE_VALUE)    {        return 0;    }      // 申請設(shè)備接口數(shù)據(jù)空間    pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);      pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);      nCount = 0;    bResult = TRUE;      // 設(shè)備序號=0,1,2... 逐一測試設(shè)備接口,到失敗為止    while (bResult)    {        ifdata.cbSize = sizeof(ifdata);          // 枚舉符合該GUID的設(shè)備接口        bResult = ::SetupDiEnumDeviceInterfaces(            hDevInfoSet,     // 設(shè)備信息集句柄            NULL,            // 不需額外的設(shè)備描述            lpGuid,          // GUID            (ULONG)nCount,   // 設(shè)備信息集里的設(shè)備序號            &ifdata);        // 設(shè)備接口信息          if (bResult)        {            // 取得該設(shè)備接口的細(xì)節(jié)(設(shè)備路徑)            bResult = SetupDiGetInterfaceDeviceDetail(                hDevInfoSet,    // 設(shè)備信息集句柄                &ifdata,        // 設(shè)備接口信息                pDetail,        // 設(shè)備接口細(xì)節(jié)(設(shè)備路徑)                INTERFACE_DETAIL_SIZE,    // 輸出緩沖區(qū)大小                NULL,           // 不需計算輸出緩沖區(qū)大小(直接用設(shè)定值)                NULL);          // 不需額外的設(shè)備描述              if (bResult)            {                // 復(fù)制設(shè)備路徑到輸出緩沖區(qū)                ::strcpy(pszDevicePath[nCount], pDetail->DevicePath);                  // 調(diào)整計數(shù)值                nCount++;            }        }    }      // 釋放設(shè)備接口數(shù)據(jù)空間    ::GlobalFree(pDetail);      // 關(guān)閉設(shè)備信息集句柄    ::SetupDiDestroyDeviceInfoList(hDevInfoSet);      return nCount;}

調(diào)用GetDevicePath函數(shù)時要注意,pszDevicePath是個指向字符串指針的指針,例如可以這樣

    int i;    char* szDevicePath[MAX_DEVICE];        // 設(shè)備路徑      // 分配需要的空間    for (i = 0; i < MAX_DEVICE; i++)    {        szDevicePath[i] = new char[256];    }      // 取設(shè)備路徑    nDevice = ::GetDevicePath((LPGUID)&DiskClassGuid, szDevicePath);      // 逐一獲取設(shè)備信息    for (i = 0; i < nDevice; i++)    {        // 打開設(shè)備        hDevice = ::OpenDevice(szDevicePath[i]);          if (hDevice != INVALID_HANDLE_VALUE)        {            ... ...        // I/O操作              ::CloseHandle(hDevice);        }    }      // 釋放空間    for (i = 0; i & lt; MAX_DEVICE; i++)    {        delete []szDevicePath[i];    }

本例的Project中除了要包含winioctl.h外,還要包含initguid.h,setupapi.h,以及連接setupapi.lib。

Q 得到設(shè)備路徑后,就可以到下一步,用CreateFile打開設(shè)備,然后用DeviceIoControl進行讀寫了吧?

A 是的。盡管該設(shè)備路徑與以前我們接觸的那些不太一樣。本是“\\.\PhysicalDrive0”,現(xiàn)在鳥槍換炮,變成了類似這樣的一副尊容:

“\\?\ide#diskmaxtor_2f040j0__________________________vam51jj0#3146563447534558202020202020202020202020#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}”。

其實這個設(shè)備名在注冊表的某處可以找到,例如在Win2000中這個名字可以位于

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Disk\Enum\0,

只不過“#”換成了“\”。分析一下這樣的設(shè)備路徑,你會發(fā)現(xiàn)很有趣的東西,它們是由接口類型、產(chǎn)品型號、固件版本、序列號、計算機名、GUID等信息組合而成的。當(dāng)然,它是沒有規(guī)范的,不能指望從這里面得到你希望知道的東西。

用CreateFile打開設(shè)備后,對于存儲設(shè)備,IOCTL_DISK_GET_DRIVE_GEOMETRY,IOCTL_STORAGE_GET_MEDIA_TYPES_EX等I/O控制碼照常使用。

今天我們討論一個新的控制碼:IOCTL_STORAGE_QUERY_PROPERTY,獲取設(shè)備屬性信息,希望得到系統(tǒng)中所安裝的各種固定的和可移動的硬盤、優(yōu)盤和CD/DVD-ROM/R/W的接口類型、序列號、產(chǎn)品ID等信息。

// IOCTL控制碼#define IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)// 存儲設(shè)備的總線類型typedef enum _STORAGE_BUS_TYPE {    BusTypeUnknown = 0x00,    BusTypeScsi,    BusTypeAtapi,    BusTypeAta,    BusType1394,    BusTypeSsa,    BusTypeFibre,    BusTypeUsb,    BusTypeRAID,    BusTypeMaxReserved = 0x7F} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;  // 查詢存儲設(shè)備屬性的類型typedef enum _STORAGE_QUERY_TYPE {    PropertyStandardQuery = 0,          // 讀取描述    PropertyExistsQuery,                // 測試是否支持    PropertyMaskQuery,                  // 讀取指定的描述    PropertyQueryMaxDefined             // 驗證數(shù)據(jù)} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;  // 查詢存儲設(shè)備還是適配器屬性typedef enum _STORAGE_PROPERTY_ID {    StorageDeviceProperty = 0,          // 查詢設(shè)備屬性    StorageAdapterProperty              // 查詢適配器屬性} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;  // 查詢屬性輸入的數(shù)據(jù)結(jié)構(gòu)typedef struct _STORAGE_PROPERTY_QUERY {    STORAGE_PROPERTY_ID PropertyId;     // 設(shè)備/適配器    STORAGE_QUERY_TYPE QueryType;       // 查詢類型     UCHAR AdditionalParameters[1];      // 額外的數(shù)據(jù)(僅定義了象征性的1個字節(jié))} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;  // 查詢屬性輸出的數(shù)據(jù)結(jié)構(gòu)typedef struct _STORAGE_DEVICE_DESCRIPTOR {    ULONG Version;                    // 版本    ULONG Size;                       // 結(jié)構(gòu)大小    UCHAR DeviceType;                 // 設(shè)備類型    UCHAR DeviceTypeModifier;         // SCSI-2額外的設(shè)備類型    BOOLEAN RemovableMedia;           // 是否可移動    BOOLEAN CommandQueueing;          // 是否支持命令隊列    ULONG VendorIdOffset;             // 廠家設(shè)定值的偏移    ULONG ProductIdOffset;            // 產(chǎn)品ID的偏移    ULONG ProductRevisionOffset;      // 產(chǎn)品版本的偏移    ULONG SerialNumberOffset;         // 序列號的偏移    STORAGE_BUS_TYPE BusType;         // 總線類型    ULONG RawPropertiesLength;        // 額外的屬性數(shù)據(jù)長度    UCHAR RawDeviceProperties[1];     // 額外的屬性數(shù)據(jù)(僅定義了象征性的1個字節(jié))} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;  // 取設(shè)備屬性信息// hDevice -- 設(shè)備句柄// pDevDesc -- 輸出的設(shè)備描述和屬性信息緩沖區(qū)指針(包含連接在一起的兩部分)BOOL GetDriveProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDevDesc){    STORAGE_PROPERTY_QUERY Query;    // 查詢輸入?yún)?shù)    DWORD dwOutBytes;                // IOCTL輸出數(shù)據(jù)長度    BOOL bResult;                    // IOCTL返回值      // 指定查詢方式    Query.PropertyId = StorageDeviceProperty;    Query.QueryType = PropertyStandardQuery;      // 用IOCTL_STORAGE_QUERY_PROPERTY取設(shè)備屬性信息    bResult = ::DeviceIoControl(hDevice, // 設(shè)備句柄        IOCTL_STORAGE_QUERY_PROPERTY,    // 取設(shè)備屬性信息        &Query, sizeof(STORAGE_PROPERTY_QUERY),    // 輸入數(shù)據(jù)緩沖區(qū)        pDevDesc, pDevDesc->Size,        // 輸出數(shù)據(jù)緩沖區(qū)        &dwOutBytes,                     // 輸出數(shù)據(jù)長度        (LPOVERLAPPED)NULL);             // 用同步I/O          return bResult;}

Q 我用這個方法從IOCTL_STORAGE_QUERY_PROPERTY返回的數(shù)據(jù)中,沒有得到CDROM和USB接口的外置硬盤的序列號、產(chǎn)品ID等信息。但從設(shè)備路徑上看,明明是有這些信息的,為什么它沒有填充到STORAGE_DEVICE_DESCRIPTOR中呢?再就是為什么硬盤序列號本是“D22P7KHE            ”,為什么它填充的是“3146563447534558202020202020202020202020”這種形式呢?

A 對這兩個問題我也是心存疑惑,但又不敢妄加猜測,正琢磨著向微軟請教呢。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多