windows的磁盘操作之七——获取当前所有的物理磁盘号

转载自:windows的磁盘操作之七——获取当前所有的物理磁盘号_bunny技术坊的技术博客_51CTO博客

原文如下:

有了前几节的基础后,本节给出一个更复杂但却非常实用的例子。

很多情况下,我们想知道当前系统下安装了多少块磁盘,他们的物理驱动器号都是多少,每一块磁盘上有多少个分区,分区号怎么分布,每个分区大小是多少。这就类似于我们打开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的简要介绍

HDEVINFO

SetupDiGetClassDevs(

IN LPGUID  ClassGuid,  OPTIONAL

IN PCTSTR  Enumerator,  OPTIONAL

IN HWND  hwndParent,  OPTIONAL

IN DWORD  Flags

);

其中,ClassGuid填入我们感兴趣的设备GUID,该函数返回满足查询条件的一组设备的信息集合的句柄,该句柄就是获取设备信息的关键钥匙。

WINSETUPAPI BOOL WINAPI

SetupDiEnumDeviceInterfaces(

IN HDEVINFO  DeviceInfoSet,

IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL

IN 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 WINAPI

SetupDiGetDeviceInterfaceDetail(

IN HDEVINFO  DeviceInfoSet,

IN PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData,

OUT PSP_DEVICE_INTERFACE_DETAIL_DATA  DeviceInterfaceDetailData,  OPTIONAL

IN DWORD  DeviceInterfaceDetailDataSize,

OUT PDWORD  RequiredSize,  OPTIONAL

OUT 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找出磁盘号。

转载自:windows的磁盘操作之七——获取当前所有的物理磁盘号_bunny技术坊的技术博客_51CTO博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值