虛擬裝置驅動程式(VxD)是 Windows 9x 核心架構的關鍵組件。本文完整解析 VxD 的線性可執行檔(LE)格式、段類型分類、模組定義檔(.DEF)撰寫、原始碼結構與建置流程,為開發 Windows 95/98 核心模組奠定堅實基礎。
VxD 採用 Linear Executable (LE) 格式,源自 OS/2 2.0,同時包含 16 位與 32 位程式碼,滿足實模式初始化與保護模式執行的雙重需求。段依運行屬性分類:
| 段類型 | 用途 | 特性 |
|---|---|---|
LCODE | 頁面鎖定程式碼/資料 | 永駐記憶體,硬體中斷處理常式必須放此段 |
PCODE | 可分頁程式碼 | VMM 可依需求換出至磁碟,大多數一般程式碼宜置於此 |
PDATA | 可分頁資料 | 同 PCODE,非即時資料首選 |
ICODE | 初始化專用程式碼 | 初始化完成後由 VMM 釋放記憶體 |
DBOCODE | 除錯專用程式碼/資料 | 僅除錯版載入,含診斷訊息處理 |
SCODE | 靜態程式碼/資料 | 即使 VxD 卸載仍保留,供動態載入/卸載的 VxD 保存狀態 |
RCODE | 實模式初始化 | 含 16 位實模式程式碼/資料 |
16ICODE | 16 位保護模式初始化 | 複製至 V86 模式用,避免編譯器產生 32 位指令 |
MCODE | 鎖定訊息字串 | 支援多國語言版本建構 |
VXD MYVXD
SEGMENTS
_LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LMGTABLE CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_LMSGDATA CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_IMSGTABLE CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_IMSGDATA CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_PMSGTABLE CLASS 'MCODE' NONDISCARDABLE IOPL
_PMSGDATA CLASS 'MCODE' NONDISCARDABLE IOPL
_PDATA CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT CLASS 'SCODE' RESIDENT
_SDATA CLASS 'SCODE' RESIDENT
_DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE
_RCODE CLASS 'RCODE'
EXPORTS
MYVXD_DDB @1
CLASS 的多個段會合併為單一邏輯段(如 _LTEXT、_LDATA 同屬 LCODE)。EXPORTS 僅匯出一個符號:裝置描述區塊 DDB(命名慣例:VxD名稱_DDB)。.386p
include vmm.inc
DECLARE_VIRTUAL_DEVICE MYVXD, 1, 0, MYVXD_Control, \
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_Control_Dispatch MYVXD
Control_Dispatch Device_Init, OnDeviceInit
Control_Dispatch Sys_Critical_Init, OnCriticalInit
End_Control_Dispatch MYVXD
end
DECLARE_VIRTUAL_DEVICE Name, MajorVer, MinorVer, CtrlProc, DeviceID, InitOrder, V86Proc, PMProc, RefData
Name:≤8 字元大寫,唯一識別碼,DDB 自動命名為 Name_DDB。CtrlProc:裝置控制函數入口,慣例 Name_Control。DeviceID:導出服務或實模式通知需向 Microsoft 申請唯一 ID,否則用 UNDEFINED_DEVICE_ID。InitOrder:載入順序,值越小越早載入;依賴其他 VxD 服務者須設較大值。可用 UNDEFINED_INIT_ORDER。Begin_Control_Dispatch / End_Control_Dispatch:定義控制函數,自動置於 VxD_LOCKED_CODE_SEG。Control_Dispatch Message, Handler:掛載控制訊息處理常式(如 Device_Init、Sys_Critical_Init)。| 段名稱 | 巨集開頭 | 巨集結尾 |
|---|---|---|
| _LTEXT | VxD_LOCKED_CODE_SEG | VxD_LOCKED_CODE_ENDS |
| _PTEXT | VxD_PAGEABLE_CODE_SEG | VxD_PAGEABLE_CODE_ENDS |
| _DBOCODE | VxD_DEBUG_ONLY_CODE_SEG | VxD_DEBUG_ONLY_CODE_ENDS |
| _ITEXT | VxD_INIT_CODE_SEG | VxD_INIT_CODE_ENDS |
| _LDATA | VxD_LOCKED_DATA_SEG | VxD_LOCKED_DATA_ENDS |
| _IDATA | VxD_IDATA_SEG | VxD_IDATA_ENDS |
| _PDATA | VxD_PAGEABLE_DATA_SEG | VxD_PAGEABLE_DATA_ENDS |
| _STEXT | VxD_STATIC_CODE_SEG | VxD_STATIC_CODE_ENDS |
| _SDATA | VxD_STATIC_DATA_SEG | VxD_STATIC_DATA_ENDS |
| _DBODATA | VxD_DEBUG_ONLY_DATA_SEG | VxD_DEBUG_ONLY_DATA_ENDS |
| _16ICODE | VxD_16BIT_INIT_SEG | VxD_16BIT_INIT_ENDS |
| _RCODE | VxD_REAL_INIT_SEG | VxD_REAL_INIT_ENDS |
; 組譯
ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 myvxd.asm
; 連結
link -vxd -def:myvxd.def myvxd.obj
; Makefile 範例
NAME=myvxd
$(NAME).vxd: $(NAME).obj
link -vxd -def:$(NAME).def $(NAME).obj
$(NAME).obj: $(NAME).asm
ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 $(NAME).asm
-coff:COFF 目標檔格式-c:僅組譯不連結-Cx:保留大小寫-D:定義條件組譯巨集(相當於 C 的 #define)-vxd:產生 VxD 檔案-def:指定模組定義檔vmm.inc、vwin32.inc、shell.inc 等VxD 開發的核心在於理解 LE 格式的段屬性、正確撰寫 .DEF 檔、善用 vmm.inc 巨集建構標準架構、並在適當的控制訊息(Sys_Critical_Init、Device_Init、Init_Complete)中完成初始化。掌握這些基礎,即可進一步開發硬體驅動、檔案系統過濾器、系統監控等核心模組。