首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

從 DOS 到 Windows:磁碟磁區讀寫與格式化的底層實作演進

     編輯:關於C++

前言:跨越時代的磁碟存取

在早期的 DOS 年代,程式設計師習慣直接操作硬體,透過 int 13h 中斷服務來讀寫磁碟磁區。隨著 Windows 9x/NT 核心架構的建立,應用程式不再擁有 Ring 0 的最高執行權限,直接呼叫 BIOS 中斷成為歷史。本文將深入探討如何在 Windows 環境下,透過 DeviceIoControl 與 VWIN32 虛擬裝置驅動程式(VxD)橋接,實現對磁碟第 0 軌第 1 磁區(啟動磁區)的讀取、寫入與格式化操作。

DOS 時代的直接硬體操作

在 16 位元的 DOS 環境中,程式碼簡潔直接:

char buffer[512];
reg.x.dx = 0;               // 磁碟機 A:
reg.x.cx = 0x0001;          // 柱面 0,磁區 1(啟動磁區)
reg.x.bx = fp_off(buffer);  // 緩衝區偏移
sreg.es = fp_seg(buffer);   // 緩衝區段地址
reg.x.ax = 0x0201;          // AH=02h 讀取,AL=01h 磁區數
int86x(0x13, ®, ®, &sreg); // 呼叫 BIOS int 13h

這段程式碼直接操作暫存器,將控制權交給 BIOS,完成實體磁碟存取。然而,這在受保護模式的 Windows 下已不可行。

Windows 下的解決方案:VWIN32 與 DeviceIoControl

Windows 9x 提供了 \\.\VWIN32 裝置介面,允許 Ring 3 的應用程式透過 DeviceIoControl 發送模擬的 int 21h 或 int 13h 請求給 VxD 執行。核心在於定義一個對應 CPU 暫存器的結構體:

#pragma pack(push, 1)
struct DIOC_REGISTERS {
    DWORD reg_ebx;
    DWORD reg_edx;
    DWORD reg_ecx;
    DWORD reg_eax;
    DWORD reg_edi;
    DWORD reg_esi;
    DWORD reg_flags;
};
#pragma pack(pop)

關鍵步驟解析

  1. 開啟 VWIN32 裝置:CreateFile("\\\\.\\VWIN32", ...) 取得裝置控制代碼。
  2. 重設磁碟機:發送 AX=0x0000 的 int 13h 重設命令。
  3. 磁頭定位:發送 AX=0x0C00 的尋軌命令,CX 指定柱面/磁區,DX 指定磁頭/磁碟機。
  4. 讀寫磁區:發送 AX=0x0201(讀取)或 0x0301(寫入),EBX 指向資料緩衝區。

完整流程範例

// 開啟裝置
hDevice = CreateFile("\\\\.\\VWIN32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);

// 1. 重設軟碟機
reg.reg_eax = 0x0000;
reg.reg_edx = driveNumber;
reg.reg_flags = 0x0001; // 預設 carry flag 為錯誤
DeviceIoControl(hDevice, VWIN32_DIOC_DOS_INT13, ®, sizeof(reg), ®, sizeof(reg), &cb, 0);

// 2. 尋軌
reg.reg_eax = 0x0C00;
reg.reg_ecx = (cylinder << 8) | sector;
reg.reg_edx = (head << 8) | driveNumber;
DeviceIoControl(hDevice, VWIN32_DIOC_DOS_INT13, ®, sizeof(reg), ®, sizeof(reg), &cb, 0);

// 3. 讀取啟動磁區
reg.reg_eax = 0x0201;
reg.reg_ebx = (DWORD)&buffer;
DeviceIoControl(hDevice, VWIN32_DIOC_DOS_INT13, ®, sizeof(reg), ®, sizeof(reg), &cb, 0);

if (!dwResult || (reg.reg_flags & 0x0001)) {
    // 處理錯誤:carry flag 為 1 表示失敗
}

注意事項與限制

  • 權限需求:存取 \\.\PhysicalDriveX 或 \\.\VWIN32 通常需要系統管理員權限。
  • 僅限 Windows 9x:VWIN32 是 Windows 9x 獨有的 VxD,Windows NT 系列(含 2000/XP/後續版本)不支援此介面,需改用 IOCTL_DISK_READ/WRITE 直接對實體磁碟操作。
  • 記憶體對齊:緩衝區位址傳遞給 VxD 時需確保在共享記憶體區域或經過鎖定,否則可能導致頁錯誤。
  • 錯誤處理:回傳的 reg_flags 中的 Carry Flag (bit 0) 為 1 代表操作失敗,AH (reg_eax 高位元組) 會包含 BIOS 錯誤碼。

總結

從 DOS 的 int 13h 到 Windows 的 DeviceIoControl + VWIN32,核心邏輯未變——設定暫存器參數、發送中斷命令、檢查狀態旗標——但執行環境從實模式移植到虛擬 86 模式監控下。理解這層映射關係,不僅有助於維護舊有系統,更能深入掌握作業系統如何虛擬化硬體資源。對於現代 Windows 開發,建議改用 Win32 API (ReadFile/WriteFile 配合 \\.\PhysicalDriveX) 或儲存體管理介面,以獲得更好的相容性與安全性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved