11.9.1 遍历磁盘容量
如下代码实现了在Windows系统中获取所有磁盘驱动器的信息。具体包括两个函数,一个用于获取驱动器类型,另一个用于获取驱动器空间信息。主函数则调用这两个函数来遍历所有逻辑驱动器并输出相应的信息。在输出驱动器空间信息时,会输出该驱动器的总大小、已用空间以及可用空间。
#include <stdio.h>
#include <Windows.h>void GetDrivesType(const char* lpRootPathName)
{UINT uDriverType = GetDriveType(lpRootPathName);switch (uDriverType){case DRIVE_UNKNOWN:puts("未知磁盘"); break;case DRIVE_NO_ROOT_DIR: puts("路径无效"); break;case DRIVE_REMOVABLE: puts("可移动磁盘"); break;case DRIVE_FIXED: puts("固定磁盘"); break;case DRIVE_REMOTE: puts("网络磁盘"); break;case DRIVE_CDROM: puts("光驱"); break;case DRIVE_RAMDISK: puts("内存映射盘"); break;default: break;}
}void GetDrivesFreeSpace(const char* lpRootPathName)
{unsigned long long available, total, free;if (GetDiskFreeSpaceEx(lpRootPathName, (ULARGE_INTEGER*)&available, (ULARGE_INTEGER*)&total, (ULARGE_INTEGER*)&free)){printf("磁盘: %s | 总计: %lld MB 已用: %lld MB 剩余: %lld MB \n",lpRootPathName, total >> 20, available >> 20, free >> 20);}
}int main(int argc,char *argv[])
{DWORD dwSize = MAX_PATH;char szLogicalDrives[MAX_PATH] = {0};// 获取逻辑驱动器号字符串DWORD dwResult = GetLogicalDriveStringsA(dwSize, szLogicalDrives);if (dwResult > 0 && dwResult <= MAX_PATH){// 从缓冲区起始地址开始char* szSingleDrive = szLogicalDrives;while (*szSingleDrive) {//printf("Drive: %s\n", szSingleDrive); // 输出单个驱动器的驱动器号// GetDrivesType(szSingleDrive);GetDrivesFreeSpace(szSingleDrive);// 获取下一个驱动器地址szSingleDrive += strlen(szSingleDrive) + 1;}}system("pause");return 0;
}
11.9.2 遍历盘符并存储
循环遍历盘符分区,并将所有盘符结构存储到std::vector<MyDriver>
定义的容器中.
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>// 将字节转换为GB单位显示的宏定义
#define ToGB(x) (x.HighPart << 2) + (x.LowPart >> 20) / 1024.0// 定义基础结构
typedef struct
{double available_space;double free_space;double total_space;
}DriverInfo;// 定义完整结构
typedef struct
{char driver_name[128];char driver_type[128];double available_space;double free_space;double total_space;
}MyDriver;using namespace std;// 获取驱动器数量
int GutDrivesCount()
{DWORD drivers;int count = 0;//获取驱动器数drivers = GetLogicalDrives();while (drivers != 0){if (drivers & 1 != 0){count++;}drivers >>= 1;}return count;
}// 获取驱动器类型
std::string GetDrivesType(const char* lpRootPathName)
{UINT uDriverType = GetDriveType(lpRootPathName);switch (uDriverType){case DRIVE_UNKNOWN:return "未知类型"; break;case DRIVE_NO_ROOT_DIR:return "路径无效"; break;case DRIVE_REMOVABLE:return "可移动磁盘"; break;case DRIVE_FIXED:return "固定磁盘"; break;case DRIVE_REMOTE:return "网络磁盘"; break;case DRIVE_CDROM:return "光驱设备"; break;case DRIVE_RAMDISK:return "内存映射盘"; break;default:break;}return "错误参数";
}// 获取盘符容量
DriverInfo GetDrivesFreeSpace(const char* lpRootPathName)
{// ULARGE_INTEGER 64位无符号整型值ULARGE_INTEGER available, total, free;DriverInfo ref;// 获取分区数据并返回DriversInfo结构体if (GetDiskFreeSpaceEx(lpRootPathName, (ULARGE_INTEGER*)&available, (ULARGE_INTEGER*)&total, (ULARGE_INTEGER*)&free)){ref.total_space = ToGB(total);ref.free_space = ToGB(available);ref.available_space = ref.total_space - ref.free_space;}return ref;
}std::vector<MyDriver> GetDriveForVector()
{DWORD count = GutDrivesCount();std::cout << "驱动器个数: " << count << std::endl;DWORD dwSize = MAX_PATH;char szLogicalDrives[MAX_PATH] = { 0 };// 获取逻辑驱动器号字符串DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);// 处理获取到的结果if (dwResult > 0 && dwResult <= MAX_PATH){// 定义两个结构, MyDriver 临时存储单个结构,ref存储所有磁盘的容器MyDriver my_driver_ptr;std::vector<MyDriver> ref;// 从缓冲区起始地址开始char* szSingleDrive = szLogicalDrives;while (*szSingleDrive){// 逻辑驱动器类型std::string type = GetDrivesType(szSingleDrive);// 获取磁盘空间信息并存入 DriverInfo 结构DriverInfo ptr;ptr = GetDrivesFreeSpace(szSingleDrive);// 填充结构数据strcpy(my_driver_ptr.driver_name, szSingleDrive);strcpy(my_driver_ptr.driver_type, type.c_str());my_driver_ptr.total_space = ptr.total_space;my_driver_ptr.free_space = ptr.free_space;my_driver_ptr.available_space = ptr.available_space;// 加入到容器中ref.push_back(my_driver_ptr);/*std::cout<< "盘符: " << szSingleDrive<< " 类型: " << type<< " 总容量: " << ptr.total_space<< " 可用空间: " << ptr.free_space<< " 已使用: " << ptr.available_space<< std::endl;*/// 获取下一个驱动器号起始地址szSingleDrive += strlen(szSingleDrive) + 1;}return ref;}
}int main(int argc,char *argv[])
{std::vector<MyDriver> ptr = GetDriveForVector();// 循环输出vector容器for (int x = 0; x < ptr.size(); x++){std::cout<< "盘符: " << ptr[x].driver_name<< " 类型: " << ptr[x].driver_type<< " 总容量: " << ptr[x].total_space<< " 可用空间: " << ptr[x].free_space<< " 已使用: " << ptr[x].available_space<< std::endl;}std::system("pause");return 0;
}
11.9.3 实现磁盘格式化
如下代码定义了一个函数FormatDisk
,用于格式化由指定为字符串的驱动器号标识的磁盘。该函数使用Shell2.dll
模块中的SHFormatDrive()
这个未导出函数实现对特定磁盘的格式化。
FormatDisk函数采用std::string
参数strDisk
,该参数指定要格式化的磁盘的驱动器号。该函数首先使用LoadLibraryA
加载Shell32.dll
库,然后使用GetProcAddress
检索SHFormatDrive
函数的地址。使用控制台应用程序的窗口句柄、要格式化的磁盘的驱动器ID(根据驱动器号计算)以及指定格式选项的标志来调用SHFormatDrive
函数。
#include <iostream>
#include <string>
#include <Windows.h>
#include <ShlObj.h>#pragma comment(lib, "Shell32.lib")// 格式化磁盘
void FormatDisk(std::string strDisk)
{HINSTANCE hInstance = ::LoadLibraryA("Shell32.dll");if (NULL == hInstance){return;}typedef DWORD(*PSHFORMATDRIVE)(HWND, UINT, UINT, UINT);PSHFORMATDRIVE SHFormatDrive = (PSHFORMATDRIVE)::GetProcAddress(hInstance, "SHFormatDrive");if (NULL == SHFormatDrive){return;}UINT uiID = strDisk[0] - 'A';// 获取控制台程序窗口句柄HWND hWnd = ::GetConsoleWindow();SHFormatDrive((HWND)hWnd, uiID, 0xFFFF, 0x0001);::FreeLibrary(hInstance);
}int main(int argc, char* argv[])
{// 传入磁盘FormatDisk("D");return 0;
}
11.9.4 移除指定磁盘
如下代码演示了如何通过 Windows API
移除指定的磁盘驱动器,包括移除盘符和卸载卷加载点。代码首先定义了一个 DeleteVolume
函数,接收一个指向字符串的指针,表示要删除的磁盘驱动器的盘符。然后,函数将盘符转换为设备名称,使用 DefineDosDeviceA
函数将其从系统中移除。接着,函数使用 DeleteVolumeMountPointA
函数删除卷加载点。最后,main
函数调用 DeleteVolume
函数四次,移除了 C:、D:、E:、F:
四个磁盘驱动器。
#include <iostream>
#include <Windows.h>// 移除指定盘符
BOOL DeleteVolume(char* lpszDriver)
{// 将盘符和Dos设备路径移除char szDeviceName[MAX_PATH] = { 0 };strcpy(szDeviceName, lpszDriver);szDeviceName[2] = '\0';if (!DefineDosDeviceA(DDD_REMOVE_DEFINITION, szDeviceName, NULL)){return FALSE;}// 卸载卷加载点if (!DeleteVolumeMountPointA(lpszDriver)){return FALSE;}return TRUE;
}int main(int argc, char *argv[])
{DeleteVolume((char*)"C:");DeleteVolume((char *)"D:");DeleteVolume((char*)"E:");DeleteVolume((char*)"F:");return 0;
}
11.9.5 输出磁盘分区表
如下代码,用于读取和分析Windows
系统上第一个物理硬盘的主引导记录MBR
。代码中定义了几个数据结构来表示MBR
及其组件,包括引导记录、磁盘分区表和磁盘签名,ShowMbr使用ReadFile
函数从硬盘读取MBR
数据,然后以十六进制格式逐字节打印MBR
数据。AnalysMbr函数提取并分析MBR
数据,打印出引导记录、磁盘签名和分区表信息。
主函数中使用CreateFileA
打开第一个物理硬盘,使用ShowMbr
函数读取MBR
数据,使用AnalystMbr
函数分析MBR
数据,然后使用CloseHandle
函数关闭文件句柄,此段代码读者在编译时需采用64位模式编译。
#include <iostream>
#include <Windows.h>// 定义数据结构体
#define BOOTRECORDSIZE 440
typedef struct _BOOTRECORD
{unsigned char BootRecore[BOOTRECORDSIZE];
}BOOTRECORD, * PBOOTRECORD;#define DPTSIZE 64
typedef struct _DPT
{unsigned char Dpt[DPTSIZE];
}DPT, * PDPT;#define DPTNUMBER 4
typedef struct _DP
{unsigned char BootSign; // 引导标志unsigned char StartHsc[3];unsigned char PatitionType; // 分区类型unsigned char EndHsc[3];ULONG SectorsPreceding; // 本分去之前使用的扇区数ULONG SectorsInPatition; // 分区的总扇区数
}DP, * PDP;typedef struct _MBR
{BOOTRECORD BootRecord; // 引导程序unsigned char ulSigned[4]; // windows磁盘签名unsigned char sReserve[2]; // 保留位DPT Dpt; // 分区表unsigned char EndSign[2]; // 结束标志
}MBR, * PMBR;void ShowMbr(HANDLE hFile, PMBR pMbr)
{DWORD dwTemp = 0;::ReadFile(hFile, (LPVOID)pMbr, sizeof(MBR), &dwTemp, NULL);for (int i = 0; i < 512; i++){printf("%2x ", ((BYTE*)pMbr)[i]);if (0 == ((i + 1) % 16)){printf("\r\n");}else if (0 == ((i + 1) % 8)){printf(" ");}}
}void AnalysMbr(MBR Mbr)
{printf("\r\n引导记录:\r\n");for (int i = 0; i < BOOTRECORDSIZE; i++){printf("%2x ", Mbr.BootRecord.BootRecore[i]);if (0 == ((i + 1) % 16)){printf("\r\n");}else if (0 == ((i + 1) % 8)){printf(" ");}}printf("\r\n磁盘签名:\r\n");for (int i = 0; i < 4; i++){printf("%02x ", Mbr.ulSigned[i]);}printf("\r\n解析分区表:\r\n");for (int i = 0; i < DPTSIZE; i++){printf("%02x ", Mbr.Dpt.Dpt[i]);if (0 == ((i + 1) % 16)){printf("\r\n");}else if (0 == ((i + 1) % 8)){printf(" ");}}printf("\r\n");PDP pDp = (PDP) & (Mbr.Dpt.Dpt);for (int i = 0; i < DPTNUMBER; i++){printf("引导标识:%02x ", pDp[i].BootSign);printf("分区类型:%02x ", pDp[i].PatitionType);printf("\r\n");printf("本分区之前扇区数:%d ", pDp[i].SectorsPreceding);printf("本分区的总扇区数:%d", pDp[i].SectorsInPatition);printf("\r\n");printf("该分区的大小:%f\r\n", (double)pDp[i].SectorsInPatition / 1024 / 1024 * 512 / 1024 / 1024);printf("\r\n");}printf("结束标志:\r\n");for (int i = 0; i < 2; i++){printf("%02x ", Mbr.EndSign[i]);}printf("\r\n");
}int main(int argc, char* argv[])
{// 打开物理硬盘设备HANDLE hFile = ::CreateFileA("\\\\.\\PhysicalDrive0",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL);if (INVALID_HANDLE_VALUE == hFile){return -1;}MBR Mbr = { 0 };ShowMbr(hFile, &Mbr);AnalysMbr(Mbr);CloseHandle(hFile);return 0;
}