在 Windows NT 核心架構(NT/2000/XP/Server 2003/Vista/7/10/11)中,應用程式無法直接存取硬體,必須透過核心模式驅動程式。DeviceIoControl 正是使用者模式與驅動程式溝通的標準介面,透過發送控制碼與資料緩衝區,實現資訊查詢、命令下發、資料交換等功能。
BOOL DeviceIoControl(
HANDLE hDevice, // 裝置控制代碼
DWORD dwIoControlCode, // 控制碼
LPVOID lpInBuffer, // 輸入緩衝區
DWORD nInBufferSize, // 輸入緩衝區大小
LPVOID lpOutBuffer, // 輸出緩衝區
DWORD nOutBufferSize, // 輸出緩衝區大小
LPDWORD lpBytesReturned, // 實際回傳位元組數
LPOVERLAPPED lpOverlapped // 非同步結構,NULL 表同步
);
| 參數 | 用途 | 備註 |
|---|---|---|
hDevice | 識別目標裝置 | 由 CreateFile 取得 |
dwIoControlCode | 指定操作類型 | 定義於 winioctl.h,前綴 IOCTL_ 或 FSCTL_ |
lpInBuffer/OutBuffer | 輸入/輸出資料 | 結構由控制碼決定,無需時填 NULL/0 |
lpOverlapped | 非同步控制 | 設 NULL 為同步阻塞呼叫 |
IOCTL_DISK_GET_DRIVE_GEOMETRY、IOCTL_DISK_GET_LENGTH_INFO、IOCTL_DISK_FORMAT_TRACKSFSCTL_LOCK_VOLUME、FSCTL_DISMOUNT_VOLUME、FSCTL_UNLOCK_VOLUMEIOCTL_STORAGE_GET_MEDIA_TYPES_EX、IOCTL_STORAGE_QUERY_PROPERTYIOCTL_CDROM_READ_TOC、IOCTL_CDROM_GET_DRIVE_SPEEDCreateFile 不僅開啟檔案,也是「打開裝置驅動程式」的關鍵:
HANDLE hDevice = CreateFile(
"\\\\.\\PhysicalDrive0", // 裝置名稱格式:\\.\DeviceName
GENERIC_READ | GENERIC_WRITE, // 或 0 僅查詢
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // 預設安全性
OPEN_EXISTING, // 必須存在
0, // 無特殊屬性
NULL); // 無模板
if (hDevice == INVALID_HANDLE_VALUE) {
// 處理錯誤:GetLastError()
}
| 裝置類型 | 命名格式 | 範例 |
|---|---|---|
| 軟碟機 | \\.\A:、\\.\B: | \\.\A: |
| 邏輯磁碟區 | \\.\C:、\\.\D: ... | \\.\C: |
| 實體硬碟 | \\.\PhysicalDriveX | \\.\PhysicalDrive0 |
| 光碟機 | \\.\CdromX | \\.\Cdrom0 |
| 磁帶機 | \\.\TapeX | \\.\Tape0 |
注意:實體硬碟不包含軟碟機與光碟機;邏輯磁碟區可為硬碟分區、光碟、USB 隨身碟、虛擬磁碟等。
BOOL GetDriveGeometry(DISK_GEOMETRY* pdg)
{
HANDLE hDevice = CreateFile("\\\\.\\PhysicalDrive0", 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) return FALSE;
DWORD junk;
BOOL bResult = DeviceIoControl(hDevice,
IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
pdg, sizeof(*pdg), &junk, NULL);
CloseHandle(hDevice);
return bResult;
}
int main()
{
DISK_GEOMETRY pdg;
if (GetDriveGeometry(&pdg)) {
ULONGLONG DiskSize = pdg.Cylinders.QuadPart *
pdg.TracksPerCylinder * pdg.SectorsPerTrack * pdg.BytesPerSector;
printf("Cylinders = %I64d\n", pdg.Cylinders.QuadPart);
printf("Tracks/cylinder = %lu\n", pdg.TracksPerCylinder);
printf("Sectors/track = %lu\n", pdg.SectorsPerTrack);
printf("Bytes/sector = %lu\n", pdg.BytesPerSector);
printf("Disk size = %I64d Bytes = %I64d MB\n",
DiskSize, DiskSize / (1024*1024));
} else {
printf("Failed. Error %lu\n", GetLastError());
}
return 0;
}
requireAdministrator\\\\.\\PhysicalDrive0IOCTL_STORAGE_GET_MEDIA_TYPES_EX 需預留陣列空間lpOverlapped=NULL),大量資料傳輸建議用非同步 + GetOverlappedResultCloseHandle 關閉裝置代碼,否則導致控制代碼洩漏掌握此核心流程,即可開發磁碟工具、光碟燒錄、硬體監控、效能測試等系統級應用。