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


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

    很多情况下,我们想知道当前系统下安装了多少块磁盘,他们的物理驱动器号都是多少,每一块磁盘上有多少个分区,分区号怎么分布,每个分区大小是多少。这就类似于我们打开windows的磁盘管理看到的那种非常清晰的列表。对于后几个问题,我们根据物理驱动器号调用第五节http://cutebunny.blog.51cto.com/301216/624567中的GetPartitionLetterFromPhysicalDrive函数,以及第三节http://cutebunny.blog.51cto.com/301216/624079中的GetDiskDriveLayout函数即可搞定。那么我们这一节的重点放在如何获得当前所有物理驱动器号上。
    先引入一个新的概念,设备GUID,它是同类设备统一并且唯一的标识码。对于磁盘,GUIDGUID_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仍旧是我们感兴趣的GUIDMemberIndex为设备在集合中的索引,从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
    );
    该函数根据上两步中的句柄和接口获取设备的详细信息数据。参数DeviceInfoSetDeviceInterfaceData在上两步中获得。输出参数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 ", 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 ", 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 ", 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 ", 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_NUMBERDeviceIoControl函数获得磁盘物理驱动器号。
    4. 将所有物理磁盘号存入数组返回。
     
    大功告成了。可能有朋友会问,GetDevicePath不是已经获得了磁盘路径么,你前面说过,这个路径不是\.PhysicalDriveX就是\.X,那我们解析一下这个字符串不就可以获得磁盘号或者盘符了么。很可惜,这里的磁盘路径出现了第三种形式,而且是毫无章法的形式。打开函数GetDevicePath中的注释行//printf("%s ", 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找出磁盘号。

  • 相关阅读:
    Qt5."Clang Code Model"一些设置
    基于element表格的合并多个行实例
    vue中,基于echarts 地图实现一个人才回流的大数据展示效果
    vue2.0 子组件props接受父组件传递的值,能不能修改的问题整理
    vue调用组件,组件回调给data中的数组赋值,报错Invalid prop type check failed for prop value. Expecte
    vue,基于element的tree组件封装
    vue父子组件相互传值的实例
    基于vant实现一个问卷调查
    css3实现倾斜转动的转盘
    0801 am使用tp框架对数据库增删改查
  • 原文地址:https://www.cnblogs.com/chaikefusibushiji/p/7475616.html
Copyright © 2020-2023  润新知