windows的磁碟操作之七——擷取當前所有的物理磁碟號

來源:互聯網
上載者:User
原創作品,允許轉載,轉載時請務必以超連結形式標明文章
原始出處 、作者資訊和本聲明。否則將追究法律責任。http://cutebunny.blog.51cto.com/301216/625577

 

有了前幾節的基礎後,本節給出一個更複雜但卻非常實用的例子。很多情況下,我們想知道當前系統下安裝了多少塊磁碟,他們的物理磁碟機代號都是多少,每一塊磁碟上有多少個分區,分區號怎麼分布,每個分區大小是多少。這就類似於我們開啟windows的磁碟管理看到的那種非常清晰的列表。對於後幾個問題,我們根據物理磁碟機代號調用第五節http://cutebunny.blog.51cto.com/301216/624567中的GetPartitionLetterFromPhysicalDrive函數,以及第三節http://cutebunny.blog.51cto.com/301216/624079中的GetDiskDriveLayout函數即可搞定。那麼我們這一節的重點放在如何獲得當前所有物理磁碟機代號上。先引入一個新的概念,裝置GUID,它是同類裝置統一併且唯一的標識碼。對於磁碟,GUID為GUID_DEVINTERFACE_DISK,具體值為{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}。windows提供一組API,可以通過GUID枚舉出所有該類型的裝置。先給出幾個相關API的簡要介紹 HDEVINFOSetupDiGetClassDevs(IN LPGUID  ClassGuid,  OPTIONALIN PCTSTR  Enumerator,  OPTIONALIN HWND  hwndParent,  OPTIONALIN DWORD  Flags);其中,ClassGuid填入我們感興趣的裝置GUID,該函數返回滿足查詢條件的一組裝置的資訊集合的控制代碼,該控制代碼就是擷取裝置資訊的關鍵鑰匙。 WINSETUPAPI BOOL WINAPISetupDiEnumDeviceInterfaces(IN HDEVINFO  DeviceInfoSet,IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONALIN LPGUID  InterfaceClassGuid,IN DWORD  MemberIndex,OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData);該函數枚舉SetupDiGetClassDevs獲得的控制代碼中包含的所有裝置。參數DeviceInfoSet填入我們上一步中獲得的控制代碼,InterfaceClassGuid仍舊是我們感興趣的GUID,MemberIndex為裝置在集合中的索引,從0開始計數,最後DeviceInterfaceData是輸出參數,儲存枚舉出的裝置介面,後續可通過此介面獲得詳細的裝置資訊。注意,參數DeviceInterfaceData.cbSize在調用前必須初始化為sizeof(SP_DEVICE_INTERFACE_DATA),這是函數的強制要求。 WINSETUPAPI BOOL WINAPISetupDiGetDeviceInterfaceDetail(IN HDEVINFO  DeviceInfoSet,IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,OUT PSP_DEVICE_INTERFACE_DETAIL_DATA  DeviceInterfaceDetailData,  OPTIONALIN DWORD  DeviceInterfaceDetailDataSize,OUT PDWORD  RequiredSize,  OPTIONALOUT PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL);該函數根據上兩步中的控制代碼和介面擷取裝置的詳細資料資料。參數DeviceInfoSet和DeviceInterfaceData在上兩步中獲得。輸出參數DeviceInterfaceDetailData儲存著裝置資訊資料,這個結構體中的成員DevicePath就是我們辛辛苦苦找尋的東西了。用它可以作為裝置名稱調用CreateFile函數開啟裝置,之後的操作,嘿嘿,你懂的… 下面是具體代碼/******************************************************************************* Function: get device path from GUID* input: lpGuid, GUID pointer* output: pszDevicePath, device paths* return: Succeed, the amount of found device paths*         Fail, -1******************************************************************************/DWORD GetDevicePath(LPGUID lpGuid, CHAR **pszDevicePath){    HDEVINFO hDevInfoSet;    SP_DEVICE_INTERFACE_DATA ifdata;    PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;    DWORD nCount;    BOOL result;     //get a handle to a device information set
    hDevInfoSet = SetupDiGetClassDevs(                    lpGuid,      // class GUID
                    NULL,        // Enumerator                    NULL,        // hwndParent                    DIGCF_PRESENT | DIGCF_DEVICEINTERFACE    // present devices                    );     //fail...    if (hDevInfoSet == INVALID_HANDLE_VALUE)    {        fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());        return (DWORD)-1;    }     pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(INTERFACE_DETAIL_SIZE);    if (pDetail == NULL)    {        return (DWORD)-1;    }    pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);     nCount = 0;    result = TRUE;     // device index = 0, 1, 2... test the device interface one by one    while (result)    {        ifdata.cbSize = sizeof(ifdata);         //enumerates the device interfaces that are contained in a device information set        result = SetupDiEnumDeviceInterfaces(                    hDevInfoSet,     // DeviceInfoSet                    NULL,            // DeviceInfoData                    lpGuid,          // GUID                    nCount,   // MemberIndex                    &ifdata        // DeviceInterfaceData                    );        if (result)        {            // get details about a device interface            result = SetupDiGetDeviceInterfaceDetail(                        hDevInfoSet,    // DeviceInfoSet                        &ifdata,        // DeviceInterfaceData                        pDetail,        // DeviceInterfaceDetailData                        INTERFACE_DETAIL_SIZE,    // DeviceInterfaceDetailDataSize                        NULL,           // RequiredSize                        NULL          // DeviceInfoData                        );            if (result)            {                // copy the path to output buffer                strcpy(pszDevicePath[nCount], pDetail->DevicePath);                //printf("%s\n", pDetail->DevicePath);                nCount++;            }        }    }     free(pDetail);    (void)SetupDiDestroyDeviceInfoList(hDevInfoSet);     return nCount;}執行完畢後,所有滿足條件的磁碟裝置名稱都儲存在字串數組pszDevicePath中。有了這個關鍵的數組,後面就可以為所欲為了。 以下是獲得所有物理磁碟號的完整代碼/******************************************************************************* Function: get all present disks' physical number* input: N/A* output: ppDisks, array of disks' physical number* return: Succeed, the amount of present disks*         Fail, -1******************************************************************************/DWORD GetAllPresentDisks(DWORD **ppDisks){    CHAR *szDevicePath[MAX_DEVICE];        // device path    DWORD nDevice;    HANDLE hDevice;    STORAGE_DEVICE_NUMBER number;    BOOL result;    DWORD readed;    WORD i, j;     for (i = 0; i < MAX_DEVICE; i++)    {        szDevicePath[i] = (CHAR *)malloc(INTERFACE_DETAIL_SIZE);        if (NULL == szDevicePath[i])        {            for (j = 0; j < i; j++)            {                free(szDevicePath[i]);            }            return (DWORD)-1;        }    }     // get the device paths    nDevice = GetDevicePath(const_cast<LPGUID>(&GUID_DEVINTERFACE_DISK), szDevicePath);    if ((DWORD)-1 == nDevice)    {        for (i = 0; i < MAX_DEVICE; i++)        {            free(szDevicePath[i]);        }        return (DWORD)-1;    }     *ppDisks = (DWORD *)malloc(sizeof(DWORD) * nDevice);    // get the disk's physical number one by one    for (i = 0; i < nDevice; i++)    {        hDevice = CreateFile(                    szDevicePath[i], // drive to open                    GENERIC_READ | GENERIC_WRITE,     // access to the drive                    FILE_SHARE_READ | FILE_SHARE_WRITE, //share mode                    NULL,             // default security attributes                    OPEN_EXISTING,    // disposition                    0,                // file attributes                    NULL            // do not copy file attribute                    );        if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive        {            for (j = 0; j < MAX_DEVICE; j++)            {                free(szDevicePath[j]);            }            free(*ppDisks);            fprintf(stderr, "CreateFile() Error: %ld\n", GetLastError());            return DWORD(-1);        }        result = DeviceIoControl(                    hDevice,                // handle to device                    IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode                    NULL,                            // lpInBuffer                    0,                               // nInBufferSize                    &number,           // output buffer                    sizeof(number),         // size of output buffer                    &readed,       // number of bytes returned                    NULL      // OVERLAPPED structure                    );        if (!result) // fail        {            fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());            for (j = 0; j < MAX_DEVICE; j++)            {                free(szDevicePath[j]);            }            free(*ppDisks);            (void)CloseHandle(hDevice);            return (DWORD)-1;        }        *(*ppDisks + i) = number.DeviceNumber;         (void)CloseHandle(hDevice);    }     for (i = 0; i < MAX_DEVICE; i++)    {        free(szDevicePath[i]);    }    return nDevice;}代碼說明:1. 調用函數GetDevicePath獲得前面所說的磁碟裝置名稱數組。2. 對每一個磁碟裝置,調用CreateFile開啟並獲得裝置控制代碼。3. 叫用作業碼為IOCTL_STORAGE_GET_DEVICE_NUMBER的DeviceIoControl函數獲得磁碟物理磁碟機代號。4. 將所有物理磁碟號存入數組返回。 大功告成了。可能有朋友會問,GetDevicePath不是已經獲得了磁碟路徑麼,你前面說過,這個路徑不是\\.\PhysicalDriveX就是\\.\X:
,那我們解析一下這個字串不就可以獲得磁碟號或者盤符了麼。很可惜,這裡的磁碟路徑出現了第三種形式,而且是毫無章法的形式。開啟函數GetDevicePath中的注釋行//printf("%s\n", pDetail->DevicePath);將這種形式的路徑列印出來,可以看到類似為\\?\ide#diskwdc_wd1600aajs-08b4a0___________________01.03a01#5&245a6b6d&0&0.0.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}\\?\ide#diskwdc_wd1600aajs-08b4a0___________________01.03a01#5&37141c12&0&0.1.0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}所以,沒辦法,我們還是得用DeviceIoControl找出磁碟號。

 

 

 

本文出自 “bunny技術坊” 部落格,請務必保留此出處http://cutebunny.blog.51cto.com/301216/625577

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.