获取硬盘和卷或分区相关信息(容量,ID,卷标名字等)

1、枚举所有硬盘

这里主要借助了setup API,这些API主要是NT4.0之后提供的一些用于操作设备的API。

枚举所有硬盘借助了SetupDiGetClassDevs与SetupDiEnumDeviceInterfaces和 SetupDiGetDeviceInterfaceDetail这三个API。

#pragma once


#ifndef DEVICE_DISK_H
#define DEVICE_DISK_H
#include <Windows.h>
#include <Setupapi.h>
#pragma comment( lib, "setupapi.lib" )
#define DevCount 1024
struct DevInterfaceDetaillArray {
    DWORD szCount;
    PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData_[DevCount];
};

int GetALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_);

int FreeALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_);

#endif
 

#include "DeviceDisk.h"

#include <iostream>
#include <string>
using namespace std;


//函数调用出错一定要记得回收内存,否则会内存泄漏。
//切记要与FreeALLDISK 成对使用。

int GetALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_) {

    HDEVINFO diskClassDevices;
    GUID diskClassDeviceInterfaceGuid = GUID_DEVINTERFACE_DISK;
    SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
    PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData;
    DWORD requiredSize;
    DWORD deviceIndex;


    //
    // Get the handle to the device information set for installed
    // disk class devices. Returns only devices that are currently
    // present in the system and have an enabled disk device
    // interface.
    //
    diskClassDevices = SetupDiGetClassDevs(&diskClassDeviceInterfaceGuid,
        NULL,
        NULL,
        DIGCF_PRESENT |
        DIGCF_DEVICEINTERFACE);
    
    if (INVALID_HANDLE_VALUE == diskClassDevices) {
        return -1;
    }


    ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    deviceIndex = 0;

    while (SetupDiEnumDeviceInterfaces(diskClassDevices,
        NULL,
        &diskClassDeviceInterfaceGuid,
        deviceIndex,
        &deviceInterfaceData)) {


        SetupDiGetDeviceInterfaceDetail(diskClassDevices,
            &deviceInterfaceData,
            NULL,
            0,
            &requiredSize,
            NULL);
            //回收掉临时内存
        if (!(ERROR_INSUFFICIENT_BUFFER == GetLastError())) {
            wprintf_s(L"122\n"); //正常情况下,就是获得122错误码,咱也不知道windows在干啥。
            if (INVALID_HANDLE_VALUE != diskClassDevices) {
                SetupDiDestroyDeviceInfoList(diskClassDevices);
            }
            return -1;
        }


        deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize);


        ZeroMemory(deviceInterfaceDetailData, requiredSize);
        deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        if (!SetupDiGetDeviceInterfaceDetail(diskClassDevices,
            &deviceInterfaceData,
            deviceInterfaceDetailData,
            requiredSize,
            NULL,
            NULL)) {
            //没有将此次的deviceInterfaceDetailData 内存返回到DevInterfaceDetailArr_中,所以在返回之前必须释放掉,防止内存泄漏。
            free(deviceInterfaceDetailData);
            //回收掉临时内存
            if (INVALID_HANDLE_VALUE != diskClassDevices) {
                SetupDiDestroyDeviceInfoList(diskClassDevices);
            }
            return -1;
        }
            
        DevInterfaceDetailArr_->deviceInterfaceDetailData_[deviceIndex] = deviceInterfaceDetailData;
        ++deviceIndex;
    }

    DWORD Err_Code = GetLastError();

    DevInterfaceDetailArr_->szCount = deviceIndex;

    //返回之前回收临时内存
    if (INVALID_HANDLE_VALUE != diskClassDevices) {
        SetupDiDestroyDeviceInfoList(diskClassDevices);
    }
    if (ERROR_NO_MORE_ITEMS == Err_Code) {
        //正常退出while的状态码:259,no more data availible。
        return 0;
    }
    return -2; //0正常执行成功,-1循环内部执行出错,-2执行出错退出循环。
}


int FreeALLDISK(struct DevInterfaceDetaillArray* DevInterfaceDetailArr_) {
    for (int i = 0; i < DevInterfaceDetailArr_->szCount; i++) {
        free(DevInterfaceDetailArr_->deviceInterfaceDetailData_[i]);
    }
    return 0;
}

2、获取硬盘信息(容量、制造商,销售商,版本,硬盘号(即硬盘在系统中显示的序号)等)

核心就是通过createfile打开硬盘设备,获得一个硬盘设备相关的处理句柄。

然后通过DeviceIoControl与对应的控制码来获取硬盘相关信息。

一个使用了这种类似方法的项目地址:GitHub - comefromezero/efiboot: a efiboot tool on windows

下面的代码只是示例,并不能直接运行。

  if (0 != GetALLDISK(&DevIn)) {
        wprintf_s(L"调用GetALLDISK出错!");
        FreeALLDISK(&DevIn);
        return -1;
    }
    HANDLE hdisk = INVALID_HANDLE_VALUE ;
    PSTORAGE_DEVICE_DESCRIPTOR pDevDesc;
    STORAGE_PROPERTY_QUERY Query;
    DWORD dwOutBytes;


    Query.PropertyId = StorageDeviceProperty;
    Query.QueryType = PropertyStandardQuery;
    
    pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)new BYTE[sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1];
    
    ZeroMemory(pDevDesc, sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1);
    pDevDesc->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 512 - 1;
    //wprintf_s(L"%d", pDevDesc->Size);
    
    //struct EFI_Disk_Info efi_disk[1024] = { 0 };
    //g_efi_disk = efi_disk;

    GET_LENGTH_INFORMATION disk_len = { 0 };
    STORAGE_DEVICE_NUMBER diskNumber = { 0 };
    DWORD sizePar = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX) * 128;
    PDRIVE_LAYOUT_INFORMATION_EX ParTable = (PDRIVE_LAYOUT_INFORMATION_EX)new BYTE[sizePar];
    ZeroMemory(ParTable, sizePar);
    int devIndex = 0;

    TCHAR szPathName[MAX_PATH + 1] = { 0 };

    for (devIndex = 0; devIndex < DevIn.szCount; devIndex++) {
        wprintf_s(L"DiskInfo:%s\n", DevIn.deviceInterfaceDetailData_[devIndex]->DevicePath);
        hdisk = CreateFile(DevIn.deviceInterfaceDetailData_[devIndex]->DevicePath, 
            GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 
            NULL,
            OPEN_EXISTING, 
            FILE_ATTRIBUTE_NORMAL, NULL);
        if (INVALID_HANDLE_VALUE == hdisk) {
            wprintf_s(L"createfile error! error_code:%d\n", GetLastError());
            return -1;
        }
        if (!DeviceIoControl(hdisk,
            IOCTL_STORAGE_QUERY_PROPERTY,
            &Query, sizeof(STORAGE_PROPERTY_QUERY),
            pDevDesc, pDevDesc->Size,
            &dwOutBytes,
            NULL)
            ){ 
            wprintf_s(L"DeviceIoControl Error! line:238 Error_Code:%d %d\n", GetLastError(),dwOutBytes);
            
            
            
        }
        if (!DeviceIoControl(hdisk, IOCTL_DISK_GET_LENGTH_INFO,
            NULL,
            0,
            &disk_len, sizeof(disk_len), &dwOutBytes, NULL)) {

            wprintf_s(L"DeviceIoControl Error! line:248 Error_Code:%d %d\n", GetLastError(), dwOutBytes); //122是正常的。

        }

        if (!DeviceIoControl(hdisk,
            IOCTL_STORAGE_GET_DEVICE_NUMBER,
            NULL,
            0,
            &diskNumber,
            sizeof(STORAGE_DEVICE_NUMBER),
            &dwOutBytes,
            NULL)) {

            wprintf_s(L"DeviceIoControl Error! line:272 Error_Code:%d %d\n", GetLastError(), dwOutBytes);

        }
        dwOutBytes = 0;
        if (!DeviceIoControl(hdisk,
            IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
            NULL,
            0,
            ParTable,
            sizePar,
            &dwOutBytes,
            NULL)) {

            wprintf_s(L"DeviceIoControl Error! line:285 Error_Code:%d %d\n", GetLastError(), dwOutBytes);

        }

        g_efi_disk[devIndex] = (struct EFI_Disk_Info*)new (struct EFI_Disk_Info);
        CloseHandle(hdisk);
        hdisk = INVALID_HANDLE_VALUE;
        //wprintf_s(L"%d %d\n", dwOutBytes, pDevDesc->Size);
        char* p_char_string = (char*)pDevDesc;
        stringstream sz_buffer;
        g_efi_disk[devIndex]->productor = std::string(&p_char_string[pDevDesc->ProductIdOffset]);
        g_efi_disk[devIndex]->version = std::string(&p_char_string[pDevDesc->ProductRevisionOffset]);
        g_efi_disk[devIndex]->vendor = std::string(&p_char_string[pDevDesc->VendorIdOffset]);
        int buffer_disk_len = disk_len.Length.QuadPart / 1024 / 1024 / 1024;
        sz_buffer << buffer_disk_len << "GB";
        g_efi_disk[devIndex]->length = sz_buffer.str();
        g_efi_disk[devIndex]->number = std::to_string(diskNumber.DeviceNumber);
        printf_s("Productor:%s\n", g_efi_disk[devIndex]->productor.c_str());
        printf_s("Version:%s\n", g_efi_disk[devIndex]->version.c_str());
        printf_s("Vendor:%s\n", g_efi_disk[devIndex]->vendor.c_str());
        printf_s("Length:%s\n", g_efi_disk[devIndex]->length.c_str());
        printf_s("Number:%s\n", g_efi_disk[devIndex]->number.c_str());

        wprintf_s(L"===================================================================================\n");
        wprintf_s(L"ParTable:\n");
        wprintf_s(L"ParTableType:%d\n",ParTable->PartitionStyle);
        wprintf_s(L"ParCount:%d\n", ParTable->PartitionCount);
        
        wprintf_s(L"Par0:\nParNum:%d\nParName:%s\n", ParTable->PartitionEntry[0].PartitionNumber,ParTable->PartitionEntry[0].Gpt.Name);
        wprintf_s(L"PatLength:%dMB\n", ParTable->PartitionEntry[0].PartitionLength.QuadPart / 1024 / 1024);
        wprintf_s(L"ParType:{%04x-%02x-%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data1,
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data2,
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data3,
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[0],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[1],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[2],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[3],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[4],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[5],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[6],
            ParTable->PartitionEntry[0].Gpt.PartitionType.Data4[7]);
        wprintf_s(L"ParGUID:{%04x-%02x-%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data1,
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data2,
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data3,
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[0],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[1],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[2],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[3],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[4],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[5],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[6],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[7]);
        
        wprintf_s(L"返回的字节数:%d\n", dwOutBytes);
        //ParTable = { 0 };
        wprintf_s(L"===================================================================================\n");
        wsprintf(szPathName, L"\\\\\?\\Volume{%04x-%02x-%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data1,
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data2,
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data3,
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[0],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[1],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[2],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[3],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[4],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[5],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[6],
            ParTable->PartitionEntry[0].Gpt.PartitionId.Data4[7]);
        wprintf_s(L"%s\n", szPathName);
    }
    delete pDevDesc;
    FreeALLDISK(&DevIn);

 3、获取卷或分区相关信息(卷标名字和文件系统格式等)

核心API就是GetVolumeInfomation来获得对应的信息。

一个使用该办法的项目地址:

GitHub - comefromezero/efiboot: a efiboot tool on windows

以下示例不能直接运行。

if (0 == GetVolumeInformation(ParName, VolumeName, 1024, NULL, NULL, NULL, FileSysName, 1024)) {
wprintf_s(L"Line:%d Err_Code:%d\n",__LINE__, GetLastError());
return -1;
}

4、获取 volume所在硬盘的硬盘号

有了硬盘号就能通过createfile创建一个硬盘设备的句柄,然后利用DeviceIoControl获取硬盘相关信息。

一个使用该办法的项目地址:

GitHub - comefromezero/efiboot: a efiboot tool on windows

以下示例不能直接运行。


    //获取分区所在硬盘


    TCHAR Buf_Par_Name[1024] = { 0 };
    memcpy(Buf_Par_Name, ParName, wstrlen(ParName)-4); //构建分区设备,用于createfile打开分区。
    //wprintf_s(L"    Line:%d ParName:%s\n",__LINE__, Buf_Par_Name);
    HANDLE h_vol = INVALID_HANDLE_VALUE;
    h_vol = CreateFile(Buf_Par_Name,
        GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);

    if (INVALID_HANDLE_VALUE == h_vol) {
        wprintf_s(L"Line:%d Err_Code:%d\n",__LINE__, GetLastError());
        return -1;
    }

    DWORD dwOutBytes = 0;
    PVOLUME_DISK_EXTENTS vol_disk_info = (PVOLUME_DISK_EXTENTS)new BYTE[sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT) * 10];
    ZeroMemory(vol_disk_info, sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT) * 10);
    if (!DeviceIoControl(h_vol,
        IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
        NULL, 0,
        vol_disk_info, sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT) * 10,
        &dwOutBytes,
        NULL)
        ) {

        wprintf_s(L"DeviceIoControl Error! line:%d Error_Code:%d %d\n",__LINE__, GetLastError(), dwOutBytes);

    }

其中VOLUME_DISK_EXTENTS结构体中就保存了硬盘号。

5、获取一个硬盘中所有的分区

 使用DeviceIoControl和控制码IOCTL_DISK_GET_DRIVE_LAYOUT_EX枚举出该硬盘的所有的分区入口项,然后就可以知道该硬盘上所有的分区数量以及其相关信息了。

6、枚举出所有的volume信息

FindFirstVolume与FindNextVolume这两个API可以枚举出所有的分区路径,然后通过GetVolumeInfomation这个API就能够获得对应的信息了。

这里有一个问题,在容量这个问题上,GetDiskFreeSpaceA这个获取的是簇的数量,这就有一个对齐的问题,这个API获得的volume容量可能与分区的实际容量不符,因为分区的时候没有文件系统,但是格式化为某个文件系统之后,文件系统对分区容量进行管理,所以出现GetDiskFreeSpaceA容量可能与分区的实际容量不符的问题,这需要注意一下。

系统中显示的volume容量与GetDiskFreeSpaceA容量一致。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
虽然简单,但是实用 HDEVINFO hDevInfo; SP_DEVINFO_DATA DeviceInfoData; DWORD i,j; int ret=0; hDevInfo = SetupDiGetClassDevs((LPGUID) &GUID;_DEVCLASS_MOUSE, 0, 0,DIGCF_PRESENT);//DIGCF_PROFILE);// /*   GUID_DEVCLASS_FDC软盘控制器   GUID_DEVCLASS_DISPLAY显示卡   GUID_DEVCLASS_CDROM光驱   GUID_DEVCLASS_KEYBOARD键盘   GUID_DEVCLASS_COMPUTER计算机   GUID_DEVCLASS_SYSTEM系统   GUID_DEVCLASS_DISKDRIVE磁盘驱动器   GUID_DEVCLASS_MEDIA声音、视频和游戏控制器   GUID_DEVCLASS_MODEMMODEM   GUID_DEVCLASS_MOUSE鼠标和其他指针设备   GUID_DEVCLASS_NET网络设备器   GUID_DEVCLASS_USB通用串行总线控制器   GUID_DEVCLASS_FLOPPYDISK软盘驱动器   GUID_DEVCLASS_UNKNOWN未知设备   GUID_DEVCLASS_SCSIADAPTERSCSI 和 RAID 控制器   GUID_DEVCLASS_HDCIDE ATA/ATAPI 控制器   GUID_DEVCLASS_PORTS端口(COM 和 LPT)   GUID_DEVCLASS_MONITOR监视器   */ if (hDevInfo == INVALID_HANDLE_VALUE){ // Insert error handling here. // return ; } // Enumerate through all devices in Set. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,&DeviceInfoData;);i++) { DWORD DataT; //LPTSTR buffer = NULL; char buffer[2048]; DWORD buffersize =sizeof(buffer); while (!SetupDiGetDeviceRegistryProperty( hDevInfo, &DeviceInfoData;, SPDRP_FRIENDLYNAME, &DataT;, (PBYTE)buffer, buffersize, &buffersize;)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Change the buffer size. //if (buffer) LocalFree(buffer); //buffer = (PSP_INF_INFORMATION)LocalAlloc(LPTR,buffersize); // <!--[if !supportEmptyParas]--><!--[endif]--> } else { // Insert error handling here. break; } } if (buffer != NULL && i == 0) { // temp.Format(""); // str += temp; } // temp.Format("%s",buffer); // str += temp; if (buffer) LocalFree(buffer); } if (i != 0) { // temp.Format(""); // str += temp; } if ( GetLastError()!=NO_ERROR && GetLastError()!=ERROR_NO_MORE_ITEMS ) { return ; } // <!--[if !supportEmptyParas]--><!--[endif]--> // Cleanup SetupDiDestroyDeviceInfoList(hDevInfo);
在C语言中,要获取磁盘卷标名称,可以使用以下步骤: 1. 首先,需要包含Windows.h头文件,这个头文件中定义了一些用于Windows系统编程的函数和数据结构。 2. 使用GetVolumeInformation函数来获取磁盘卷标名称。该函数的原型如下: BOOL GetVolumeInformationA( LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize ); 其中,lpRootPathName是一个指向包含卷标的根路径的字符串,比如"C:\";lpVolumeNameBuffer是用来存放卷标名称的缓冲区;nVolumeNameSize是缓冲区大小;其他的参数可以传入NULL。 3. 创建一个字符数组,用来存储卷标名称。 4. 调用GetVolumeInformation函数,并传入磁盘根路径和字符数组作为参数。 5. 如果函数返回TRUE,表示获取卷标名称成功,可以通过打印字符数组的值来查看卷标名称。 以下是一个示例代码: ```c #include <Windows.h> #include <stdio.h> int main() { char volumeName[MAX_PATH]; char rootPath[] = "C:\\"; if (GetVolumeInformationA(rootPath, volumeName, sizeof(volumeName), NULL, NULL, NULL, NULL, 0)) { printf("磁盘卷标名称: %s\n", volumeName); } else { printf("无法获取磁盘卷标名称\n"); } return 0; } ``` 以上是用C语言获取磁盘卷标名称的方法。注意,在Windows系统上,不是所有的磁盘都会有卷标名称,所以有可能获取到的名称为空。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值