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;
}