一、VxD介紹
本文介紹VxD的作用。如果Windows 95提供的標准VxD對你的硬件或者軟件不能提供100%的兼容支持,你需要為你的硬件或者軟件(包括16位和32位軟件)創建VxD。如果你想讓Windows用戶使用你的硬件或者軟件的某些新特征,你也可以創建VxD。
本文介紹如何寫VxD,講述了創建VxD所需的結構、過程和調用,還給出了創建和測試VxD的步驟。VxD可以是靜態的或者動態裝載的,下面的內容主要講述靜態VxD,不過關於格式和功能的內容兩者都適用。
二、什麼是VxD
VxD是一個管理例如硬件設備或者已安裝軟件等系統資源的32位可執行程序,使得幾個應用程序可以同時使用這些資源。Windows通過使用VxD允許基於Windows的應用程序實現多任務。VxD在與Windows的連接工作中處理中斷,並在不影響其它應用程序的執行的情況下為特定的應用程序執行I/O操作。大多數VxD管理硬件設備,也有一些VxD管理或代替與之相關的軟件,例如ROM BIOS例程。VxD可以包含必須在相應設備上執行的設備相關代碼,也可以依靠其它軟件去執行這些對設備的操作。任何情況下,VxD都會為每一個應用程序保留該設備狀態的記錄,保證無論何時一個應用程序繼續執行該設備均處於正確狀態。
一些VxD僅僅管理已安裝軟件,例如MS-DOS設備驅動程序或者TSR程序,這樣的VxD通常包含仿真這些軟件或者保護這些軟件用於正在運行的應用程序的數據的代碼。VxD有時還用於提高已安裝軟件的性能,Intel兼容CPU執行32位的VxD比執行16位的MS-DOS設備驅動程序或者TSR程序有更高的效率。
三、標准VxD
Windows包括多種VxD,用於支持公共硬件設備和可安裝軟件。在某些情況下,可能需要修改VxD以提供新的特征或者支持非標准硬件。
Windows提供許多不准備修改,但能夠輔助支持其他VxD的VxD。例如:許多VxD使用V86內存管理器(V86MMGR)和虛擬可編程中斷控制器設備(VPICD)提供的功能保存V86模式內存和允許硬件中斷請求。要取得開發VxD的幫助,Windows 95設備驅動程序開發工具包(DDK)包括了大量可用設備驅動程序的源代碼。
四、創建VxD
你可以通過修改VxD例子程序或者自己手工創建來創建VxD。你可以用匯編語言來寫VxD,也可以用高級語言(例如C語言)來寫一部分VxD。
要創建一個VxD,需要以下步驟:
1、閱讀硬件手冊中關於描述這種型號硬件VxD的章節。
2、寫出所需的控制過程,VxD服務和API函數。
3、建立為VxD標識適當模塊名的模塊定義文件,並引出需要的設備描述塊。
4、匯編連接VxD。
5、用調試版Windows 95測試VxD,要獲得更多關於調試VxD的信息,請參閱相關資料(可以用Soft-ICE調試——譯者注)。
6、為VxD和相關文件建立安裝文件(INF文件),通過修改注冊信息和向Windows的SYSTEM目錄和相關目錄拷貝文件來安裝VxD。
7、建立最終發行軟件包。
五、你需要怎樣開始
本文假定你是一位有經驗的匯編語言程序員,而且熟悉Intel兼容處理器的指令集和系統結構。在某些特殊情況下,你還應該懂得下列內容:
保護模式和虛擬8086(即V86——譯者注)模式。
平坦內存模式
中斷和異常處理
保護和特權級
段和頁式內存管理以及錯誤處理
輸入和輸出保護以及錯誤處理
本文也假定你已經熟練了解專門硬件的特征和相應的ROM BIOS例程以及其他可安裝軟件。
六、寫一個VxD
許多情況下,寫一個VxD用來代替一個由Windows 95提供的標准VxD。然而,大多數情況下,寫一個VxD是用來支持新硬件設備或者軟件的,在這
種情況下,通常手工創建一個VxD比修改已經存在的VxD要容易,原因是大多數VxD都是設備相關的。然而,已存在VxD的源代碼需要盡可能地仔
細分析,原因是它們可能包含通用的格式和結構,以及說明怎樣使用VMM和VxD服務去實現有用的功能。
寫一個VxD需要下列步驟:
1、建立包含VxD各個段,VxD聲明,設備控制過程,處理系統控制消息過程的基本部分和API過程的基本部分的VxD框架。
2、加入實模式初始化過程(可選)。
3、完成處理初始化消息的過程。這些過程應該能夠初始化控制塊,分配全局內存以及安裝中斷、I/O捕獲和頁錯誤回調過程。
4、完成處理不同中斷和錯誤的回調過程。
5、為服務加入服務表定義和聲明(可選)。
6、完成API過程(可選)
7、完成處理系統控制消息的過程以建立和刪除虛擬機。
在寫一個VxD的過程中,你可以安裝該VxD並在調試器控制下運行Windows,在該VxD中設置斷點監視該VxD管理的中斷,這樣可以幫助你查明該VxD是否正確工作。
1、VxD段
VxD可以包含下面5個段的一些組合:
1、VxD_CODE段:保護模式代碼段(必須)。該段包含VxD系統控制過程、回調過程、服務和API過程。該段用宏VxD_CODE_SEG和VxD_CODE_ENDS
定義開始和結束,也可命名為_LTEXT。
2、VxD_DATA段:保護模式數據段(必須)。該段包括設備描述表、服務表和部分VxD全局數據。該段用宏VxD_DATA_SEG和VxD_DATA_ENDS定義開
始和結束,也可命名為_LDATA。
3、VxD_ICODE段:保護模式初始化代碼段(可選)。該段一般包括只在VxD初始化過程中使用的過程和服務,VMM在Init_Complete消息發生後丟棄
此段。該段用宏VxD_ICODE_SEG和VxD_ICODE_ENDS定義開始和結束,也可命名為_ITEXT。
4、VxD_IDATA段:保護模式初始化數據段(可選)。該段一般包括初始化過程和服務使用的數據,VMM在Init_Complete消息發生後丟棄此段。該
段用宏VxD_IDATA_SEG和VxD_IDATA_ENDS定義開始和結束,也可命名為_IDATA。
5、VxD_REAL_INIT段:實模式初始化段(可選)。該段包含實模式初始化過程和數據,VMM在裝載VxD其它部分之前調用此過程,過程返回後丟棄
此段,該段用宏VxD_REAL_INIT_SEG和VxD_REAL_INIT_ENDS定義開始和結束,也可命名為_RTEXT。
除實模式初始化段以外,所有代碼和數據段均為32位平坦內存模式的保護模式段,這就是說定義在保護模式段中的過程和數據均為32位的偏移
量。當VMM裝載VxD時,按照VxD在內存中的實際位置修正所有的偏移量。因此,在保護模式段中使用普通OFFSET命令(偽操作,下同——譯者注)
處應該使用OFFSET32宏,OFFSET32宏定義的偏移量為連接器確定了正確的偏移量修正信息。
VxD不能改變CS、DS、ES和SS段寄存器,VxD能夠使用FS和GS段寄存器。
2、保護模式指令
VxD的源程序文件必須以.386p命令開始,以通知匯編器允許保護模式指令。雖然VxD工作在0特權級,但也不應該用保護模式指令去修改CPU的
運行,例如修改全局描述符(選擇子——譯者注)或中斷描述符以及修改任務狀態段或寄存器,這樣做可能會對Windows運行有不利影響。唯一的
例外情況是當該VxD為虛擬數學協處理器設備驅動程序(VMCPD),允許修改CR0寄存器中的80387位。
3、包含(Include)文件
包含文件定義了VxD需要的宏、結構、符號和服務表,用於聲明段和過程以及使用VMM和其它VxD服務。下面是每個包含文件包含的公共服務定義、
宏和符號定義列表:
1、VMM.INC:包含所有的VMM服務以及所需的宏和符號,例如Declare_Virtual_Device和VMMCall。
2、DEBUG.INC:包含在調試終端上輸出信息和執行各種數據檢查的宏。這些宏的功能由定義了調試符號的VxD在匯編時該文件生成的代碼實現。
3、VPICD.INC:包含為虛擬可編程中斷控制器設備(VPICD)定義的所有服務、宏和符號。VPICD處理所有的中斷,所以許多VxD需要VPICD服務。
4、SHELL.INC:包含虛擬外殼設備提供的公共服務的定義。虛擬外殼設備提供對例如MessageBox這樣的Windows函數的調用,可以讓VxD顯示對話框。
4、VxD聲明
每一個VxD都要聲明一個名稱、一個版本號、一個初始化順序和一個設備控制過程,許多虛擬設備驅動程序還聲明一個設備標識和一些API過程。
VxD一般使用Declare_Virtual_Device宏來實現這些聲明,例如:
Declare_Virtual_Device VSAMPLED, 4, 0, VSAMPLED_Control, \
VSAMPLED_Device_ID, VSAMPLED_Init_Order, \
VSAMPLED_V86_API_Handler, \
VSAMPLED_PM_API_Handler
本例聲明了一個VxD實例——VSAMPLED V4.0,在對應的源文件必須定義名字為VSAMPLED_Control的設備控制過程。符號VSAMPLED_Device_ID和
VSAMPLED_Init_Order說明非標准VxD的標識和初始化順序,該VxD支持V86模式和保護模式API過程。
VMM用宏定義的信息來初始化VxD並發送系統控制消息給VxD,並且允許MS-DOS應用程序、設備驅動程序和TSR調用VxD。為了使VMM存取這些信
息,相應的宏建立一個設備描述塊(DDB)並將其保存在保護模式數據段中(DDB的格式與VxD_Desc_Block結構相同),宏為DDB建立了一個必須
在VxD連接時被顯式引出的標號。在上例中,DDB的名稱是VSAMPLED_DDB。
5、VxD標識(ID)
一個VxD提供一個VxD標識,以區別於其它VxD。VMM動態連接例程使用VxD標識為合適的VxD連接服務調用,如果VxD提供服務或者提供V86模式和
保護模式API過程以及其它需要唯一標識的情況,VxD就必須有唯一標識。雖然標准VxD使用預定義VxD標識(符號定義在VMM.INC文件中),支持
新設備和新軟件接口的VxD還是必須全部有新標識。為了防止與其他新VxD沖突,Microsoft通過請求和注冊標識來保證沒有其它廠商使用自己的VxD
的標識,Microsoft保留0—01FFH之間的所有VxD標識自己使用。不提供服務或者API過程,或者不需要唯一標識的VxD應該使用Undefined_Device_ID符號來定義VxD標識。
6、初始化順序
每一個VxD都有一個用於指定VMM應該何時初始化該VxD的初始化順序值,VMM按照該值從小到大的順序初始化虛擬機(VM——譯者注)。如果兩個或
者兩個以上的VxD有相同的值,VMM會按照SYSTEM.INI文件中出現的順序來初始化,但指定順序是沒有保證的。
對於需要調用其它VxD服務或者需要在其它VxD之前攔截中斷的VxD,初始化順序是很重要的。如果一個VxD需要在標准VxD之前或者之後初始化,
它的初始化順序值應該通過在標准VxD預定義的初始化順序符號(在VMM.INC文件中定義)上加上或者減去一個小數值來創建。
如果一個VxD不需要初始化順序值,應該使用Undefined_Init_Order符號代替初始化順序值。
7、設備控制過程
每一個VxD都有一個設備控制過程,VMM通過調用此過程給VxD發送VxD系統控制消息。系統控制消息指導VxD完成動作,例如自身初始化或者通
知VxD虛擬機的變化(例如創建虛擬機)等。大多數VxD通過使用Begin_Control_Dispatch、Control_Dispatch和End_Control_Dispatch
宏來定義設備控制過程,例如:
Begin_Control_Dispatch VSAMPLED
Control_Dispatch Sys_Critical_Init, VSAMPLED_Crit_Init
Control_Dispatch Device_Init, VSAMPLED_Device_Init
Control_Dispatch Sys_Critical_Exit, VSAMPLED_Crit_Exit
End_Control_Dispatch VSAMPLED
上例中,宏創建了一個名字為VSAMPLED_Control的設備控制過程,並生成了檢查Sys_Critical_Init、Device_Init和Sys_Critical_Exit消息
的指令。當這些消息發送到該過程時,該過程通過控制相應的過程(例如SAMPLED_Crit_Init)來處理消息,這些消息處理過程必須在VxD中定義。
七、系統控制消息
VMM發送系統控制消息給VxD,以通知VxD影響系統和虛擬機的變化。大多數VxD需要跟蹤虛擬機的創建和狀態,所以無論何時創建、初始化或者
終止虛擬機,VMM都會發送消息給VxD。VMM也會在執行焦點移動到一個虛擬機或者從一個虛擬機移走時,以及虛擬外殼設備需要給用戶顯示一個消息框時發送消息給VxD。
下面是公共消息和VxD應該怎樣處理這些消息的方法列表:
Begin_Message_Mode消息:當虛擬外殼設備需要給用戶顯示一個消息框但不能使用系統虛擬機和Windows函數時VxD收到此消息。虛擬鍵盤、鼠標
和顯示設備保存當前狀態,允許任何消息模式服務並為消息模式處理初始化相應設備。
Create_VM消息:這是當一個新的虛擬機被創建時VxD收到的第一條消息。VxD應該初始化與虛擬機有關的數據,特別是控制塊。
Debug_Query消息:VxD從WDEB386調試器收到此消息。VxD可以顯示調試列表和從調試終端讀取用戶命令。
Destroy_VM消息:這是VxD收到的第三條虛擬機終止消息。Simulate_Int和Exec_Int服務對獲得此消息的虛擬機不再有效。
Device_Init消息:這是VxD收到的第二條消息。允許中斷,大多數VxD分配和拷貝初始狀態到系統虛擬機控制塊中的設備指定部分,安裝中斷回
調函數和I/O保護異常以及指定實例數據。這時,Simulate_Int和Exec_Int服務變得有效。
End_Message_Mode消息:當虛擬外殼設備不再需要顯示消息框時VxD收到此消息。虛擬鍵盤、鼠標和顯示器設備恢復獲得此消息的虛擬機以前保存
的狀態,禁止任何消息模式服務。
Init_Complete消息:這是VxD收到的第三條消息,也是最後一條與系統初始化有關的消息。雖然大多數VxD都不處理此消息,但使用V86內存的
VxD應該在此消息返回前定位和申請內存。當VxD返回此消息時,VMM丟棄VxD的初始化代碼和數據段。
Query_Destory消息:當虛擬外殼設備需要決定是否可以刪除虛擬機時VxD收到此消息。VxD可以通過設置進位標志(CF——譯者注)返回以阻止虛擬機被刪除,在這種情況下VxD應該使用SHELL_Message服務來通知用戶問題。
Reboot_Processor消息:當用戶試圖重新啟動計算機時VxD收到此消息。可以重新啟動計算機的VxD,例如鍵盤設備應該完成該工作。
Set_Device_Focus消息:當執行焦點從一個虛擬機移動到另一個虛擬機時VxD收到此消息。VxD恢復硬件設備到與虛擬機有關的狀態。如果VxD使
用I/O捕獲管理沒有執行焦點時的虛擬機,VxD應該盡可能地移走太多的I/O捕獲,使虛擬機運行盡可能地快一些。
Sys_Critical_Exit消息:這是VxD收到的最後一條消息。禁止中斷,Simualte_Int和Exec_Int服務不再有效。VxD應該復位與之相關的硬件
設備,保證能夠無問題地返回到實模式。
Sys_Critical_Init消息:這是VxD收到的第一條消息。中斷仍然不被允許,所以VxD應該盡可能快地完成任務。大多數VxD完成下列任務:
安裝和初始化需要支持來自設備的硬件中斷和來自VMM或者其它VxD的軟件中斷的任何函數,為設備提供需要單獨使用V86模式內存頁的申請,例
如虛擬顯示設備申請顯示內存。初始化VxD服務需要的任何數據,這通常包括讀取SYSTEM.INI文件中的設置。當處理此消息時,Simualte_Int和Exec_Int服務必須不被使用。
Sys_VM_Init消息:在Init_Complete消息之後VxD收到此消息。VxD應該初始化系統虛擬機的硬件和軟件狀態。如果VxD設置進位標志返回,VMM
終止所有進程並退出Windows。
Sys_VM_Terminate消息:這是VxD收到的第一條系統虛擬機終止消息。VxD可以開始為虛擬機終止做准備。Simulate_Int和Exec_Int服務有效,系
統虛擬機總是最後一個被終止的虛擬機。
System_Exit消息:這是當系統終止時VxD收到的第一條消息。VMM在發送Sys_VM_Terminate消息之後發送此消息,允許中斷,但Simualte_Int
和Exec_Int服務不再有效。如果此消息來自一個致命錯誤的結果,VxD可以通過修改系統虛擬機的內存以恢復系統狀態,使得Windows能夠終止而
不死機。
VM_Critical_Init消息:這是當一個新的VxD(虛擬機——譯者注)被創建時VxD收到的第二條消息。VxD可以通過設置進位標志返回以阻止虛擬
機被建立。禁止中斷,Simualte_Int和Exec_Int服務不再有效。
VM_Init消息:這是當一個新的VxD被創建時VxD收到的第三條消息。VxD應該初始化虛擬機的硬件和軟件狀態,例如虛擬顯示設備執行INT 10H功
能設置初始顯示模式。
VM_Not_Execute消息:這是VxD收到的第二條虛擬機終止消息(如果虛擬機已經被虛擬外殼設備刪除,這是收到的第一條消息)。VxD可以通過檢查
EDX寄存器中的標志來查明終止原因。Simulate_Int和Exec_Int服務對獲得此消息的虛擬機不再有效。
VM_Resume消息:當虛擬機的執行被恢復時VxD收到此消息,例如切換到前台時。VxD應該鎖定任何資源和為虛擬機重新開始准備內部結構。如果
VxD設置進位標志返回,VMM不恢復執行虛擬機。
VM_Suspend消息:當虛擬機已經被掛起時VxD收到此消息,例如切換到後台時。VxD應該解鎖任何與虛擬機有關的資源。
VM_Terminate消息:這是VxD收到的第一條虛擬機終止消息。VxD可以開始准備虛擬機的終止。Simulate_Int和Exec_Int服務有效。