VxD入門教程
1.背景知識?????
??為了看懂本篇所給的例子,需要C,?匯編及Windows?設備驅動程序的相關知識。?
??
???
??2.開發工具??
???
??需要?Micros以下采??
用?VC++?6.0?為例)??
???
??3.目的??
???
??利用以上所列的開發工具,編寫一個動態裝入的?VxD,?利用該VxD可以讀取內存?
地址0??
處的中斷向量表。??
???
??4.開始??
???
??第一步:??
???
??用?VC++?新建一個工程,取名為?MiniVxd,?類型為?Win32?App?或?Console?App?
因為V??
C++不提供直接生成??
???
??VxD的App?Wizard,所以只好自己在以上兩種App中選擇一個,然后再進行手工修?
改一下??
,需要修改的內容??
???
??只有一處,即在?Link?的命令行上加上一個選項??
???
???/VXD??
???
??第二步:??
???
??新建一個空文件,在其中輸入以下代碼:??
???
??TITLE?MINIVXD?-?By?Ding?Kai??
???
??.386p??
???
??include?vmm.inc??
???
???
??MINIVXD_DYNAMIC?EQU?1??
???
??;?定義設備驅動程序塊?DDB,?由于是動態裝入的,所以設備ID和裝入順序可以取?
未定??
義值.??
???
??DECLARE_VIRTUAL_DEVICE?MINIVXD,?1,?0,?MsgDispatch,UNDEFINED_DEVICE_ID,?
??
???
???Undefined_Init_Order,?0,?0??
???
??VXD_LOCKED_CODE_SEG??
???
??;?定義消息派遣表,本例中只需要一條消息,即W32_DEVICEIOCONTROL,用于從?
Win32Ap??
p中利用??
???
??;?DeviceIoControl?API函數同本VxD進行通訊.??
???
???
??BeginProc?MsgDispatch??
???
??Control_Dispatch?W32_DEVICEIOCONTROL,?W32DeviceIoControl,?sCall,??
???
???
???clc??
???
???ret??
???
??EndProc?MsgDispatch??
???
???
??VXD_LOCKED_CODE_EN???
??END??
???
???
??將文件存盤,文件名取為?VxdStub.asm,?然后用下列命令編譯該文件:??
???
??Aml?-coff?-W2?-DBLD_COFF?-DIS_32?-c?-Cx?-DMASM6?-I\95DDK\INC32??
VxdStub.asm??
???
???
??這將會生成?vxdstub.obj,將此OBJ文件加入到工程文件中。??
???
???
??第三步:??
???
??創建一個?C?語言文件,文件名取為?MiniVxd.c,在文件中輸入以下代碼:??
??#define?WIN40SERVICES??
???
??#pragma?warning?(disable:4229)??
???
??#include??
???
??#define?WANTVXDWRAPS??
???
??#pragma?intrinsic(memcpy)??
???
??#pragma?VxD_LOCKED_DATA_SEG??
???
???
??//?此處可以定義任何在VxD中需要的全局變量.??
???
??char?AnyData[200];??
???
??#pragma?VxD_LOCKED_CODE_SEG??
???
??///////////////////////////////////////////??
???
??DWORD?__stdcall?GetMemory(?DWORD?dwDDB,?PDIOCPARAMETERS?pD?)??
???
??{??
???
???BYTE?*p;??
???
??//?此處忽略了參數檢查,實際應用中切不可如此?!!??
???
???p?=?(PBYTE)pD->lpvOutBuffer;??
???
???memcpy(p,?0,?1024);?//?讀取中斷向量表,共?1024?字節??
???
???return?1024;??
???
??}??
???
??///////////////////////////////////////////////////////??
???
??/*?Win32?interface?*/??
???
??///////////////////////////////////////////////////////??
???
??int?__stdcall??
???
??W32DeviceIoControl(?DWORD?dwIoCtrlCode,?/*ecx*/??
???
??DWORD?dwDDB,?/*ebx*/??
???
??DWORD?pDIOCParams?)?/*esi*/??
???
??{??
???
???PDIOCPARAMETERS?pD;??
???
???pD?=?(PDIOCPARAMETERS)pDIOCParams;??
???
???if?(?dwIoCtrlCode?==?DIOC_OPEN?||??
???
???dwIoCtrlCode?==?DIOC_CLOSEHANDLE)??
???
???return?0L;??
???
???//?Init?returned?value??
???
???if?(pD->lpcbBytesReturned)??
???
???*(DWORD?*)pD->lpcbBytesReturned?=?0;??
???
???if?(dwIoCtrlCode==1)?{?//?1?=?DeviceIoControl代碼??
???
???GetMemory(dwDDB,?pD);??
???
??}??
???
??else??
???
???return?ERROR_NOT_SUPPORTED;??
???
???return?0;??
???
??}??
???
??將本文件加入到工程文件中.??
???
???
??第四步:??
???
??創建一個模塊定義文件,此文件將要定義最終生成的VxD文件的段屬性并輸出設備?
驅動??
程序塊,??
???
??輸入下面的代碼,并將文件存為?MiniVxd.def,同時將其加入到工程文件中.??
???
??VXD?MINIVXD?DYNAMIC??
???
??DESCRIPTION?'Written?by?Ding?Kai'??
???
??SEGMENTS??
???
??_LTEXT?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_LDATA?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_TLS?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_BSS?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_ITEXT?CLASS?'ICODE'?DISCARDABLE??
???
??_IDATA?CLASS?'ICODE'?DISCARDABLE??
???
??_PTEXT?CLASS?'PCODE'?NONDISCARDABLE??
???
??_PDATA?CLASS?'PDATA'?NONDISCARDABLE?SHARED??
???
??HEAPSIZE?10240??
???
??STACKSIZE?40960??
???
??EXPORTS??
???
??MINIVXD_DDB?@1??
???
???
??當然,其中有些段在本程序中不存在,此處列出來是想將此文件做為一個模板以?
供以??
后使用。??
???
???
??第五步:??
???
??加入本工程文件需要的最后一個,VxdWarps.clb,?這個文件是DDK的LIB目錄中.?
??
???
??第六步:??
???
??所需的四個文件已經全部加入完畢,它們是:??
???
??vxdstub.obj??
???
??minivxd.c??
???
??minivxd.def??
???
??vxdwarps.clb??
???
???
??在進行make之前請檢查一下文件路徑,?在?Include?中一定要包含?DDK?目錄中的?
INC3??
?
2?目錄.??
???
??確認無誤后可以按?F7?鍵進行?Make?了。??
???
???
??結果會在?DEBUG?目錄或?Release?目錄?(依賴于工程文件的設置)?生成?
MiniVxd.vxd??
文件。??
???
???
??至此,一個小小的Vxd文件生成完畢,?可以在程序中用下面的代碼與本VxD進行通?
訊.??
???
???
???
??BYTE?buffer[1024];??
???
??DeviceIoControl(hVxd,?1,?NULL,?NULL,?buffer,?1024,?NULL,?0);??
???
???
??結果,當前的中斷向量表就會出現在?buffer?數組中。??
???
??本文不再提供完整的測試程序,需要的話請與作者聯系??
???
??5.小結??
???
???
??本文用一個簡單的示例介紹了如何在?Windows?95?下編寫可動態安裝的?VxD,?這?
種方??
法及用這種方法??
???
??編寫的VxD在Windows?98?下同樣適用。然而,在?Windows?NT?不能采用這種方法?
??
???
???
???
???
*****************************?
**??
*******************************************??
???
??標?題:?VxD世界——虛擬的Windows世界??
???
???
??從事Windows系統編程的讀者一定聽說過VxD──這個在Windows(注:指Windows?
?3.1??
/95/98,??
???
??非Windows?NT)的世界里無所不能的超級武器。迄今為止,越來越多的人有了深?
入了??
解Windows的愿望,??
???
??這也使得VxD技術愈來愈受到重視。VxD,意即Virtual?Something?Driver,這里?
的x就??
是指Something。比如??
???
??說鍵盤驅動程序VKD、鼠標驅動程序VMD等。在許多人的腦海中,只有硬件開發者?
才會??
用到VxD,其實不??
???
??然,對于軟件開發來說,VxD也是無所不能的。在Windows3.1下這點還不明顯,?
而在W??
indows95中,隨著??
???
??線程與局部化概念的引入,想控制系統的全部資源變得愈來愈困難。舉個簡單的?
例子??
,由于32位的Windows??
???
??應用程序擁有獨立的4GB線性地址空間,在Windows?3.1下常用的Windows應用程?
序之間??
通信及共享變量的??
???
??方法不再完全適用了,想做些“出格”的事,比如說截獲別的應用程序的消息,?
變得??
愈發困難了。就在您一??
???
??愁莫展的時候,采用VxD技術或許會令您“豁然開朗”──既然操作系統能控制?
全部資??
源,那么與操作系統??
???
??享有同樣最高權限的VxD(或者干脆說作為操作系統一部分的VxD)也一定能夠幫?
助您??
完成“出格行為”。??
???
??為什么VxD有如此神通?最根本的原因,是由于VxD運行在系統的Ring?0級,而用?
SDK(??
或現在大家熟知的??
???
??VC++、BC++、Borl?and?C++?Builder、VB、Delphi)開發出的應用程序運?
行在??
Ring?3級。在80x86??
???
??保護模式下,運行在Ring?0級的VxD擁有系統最高權限(操作系統也運行在?
Ring?0級)??
。??
???
??要想真正掌握VxD技術,您必須:??
???
???對80x86的保護模式有清楚的認識;??
???
???深入理解Windows的運行機制;??
???
?
???熟悉VxD本身的運行機制。??
???
??對于保護模式,目前國內市面上有一些參考書籍,希望您能硬著頭皮看幾遍。雖?
說?不??
能使人茅塞頓開,卻也??
???
??對保護模式能有個比較清楚的認識。??
???
???
??讓我們先來認識一下Windows本身吧。??
???
???
??虛擬的Windows世界??
???
???
??運行在Windows95下的幾種應用程序:DOS應用程序、Win16應用程序、Win32應用?
程序??
。其中DOS?應用程??
???
??序大多運行在字符模式,而Win16/Win32?應用程序卻是運行在圖形模式下的。為?
了使??
這幾種運作方式大相??
???
??徑庭的應用程序能“和平共處”,Windows采用了虛擬機(Virtual?machine)的?
方式??
。每個DOS應用程序??
???
??運行在一個獨立的DOS?VM中,使得這個愣頭青似的DOS應用程序感到自己控制著?
所有的??
資源,它可以肆意??
???
??地在它認為的全屏上涂涂改改,在它以為自己獨占的硬盤上讀出寫入(微軟在設?
計DO??
S時怎么也想不到PC機??
???
??硬件的發展如此迅速)。而所有的Windows應用程序,不管是16位的,還是32位?
的,都??
運行在同一個System??
???
???VM中。這是由于Windows?應用程序守規矩得多,熟悉Windows編程的讀者一定對?
句柄??
(Handle)這個概念??
???
??有非常深刻的印象。Windows應用程序的一舉一動都是通過各種各樣的句柄(?
HWND、H??
DC、HANDLE、??
???
??HMOUDLE等)來實現的,正是通過句柄這個中介,使得系統有機會在同一個?
System?VM??
中協調多個Windows??
???
???應用程序。不信嗎?好,讓我們做個實驗(我假定您已經安裝了Softice?for??
Win95??
),啟動Windows95,啟動??
???
??結束之后,不要運行任何DOS應用程序,按下Control+D激活Softice(在有的?
Softic??
e的缺省安裝中,激活??
???
??Softice的熱鍵是Alt+D),然后敲入指令:??
???
??:vm??
???
???
??VM?Handle?Status?High?Addr?VM?ID?Client?Regs??
???
??C39200E8?00001862?C3800000?00000001?C3449F70??
???
???
??從Softice的輸出可以看到這時只有一個VM,它的ID是1。??
???
???
??按Control+D返回Windows桌面,這時,再運行幾個Windows應用程序,不管是?
16位的??
,還是32位的。重復??
???
??剛才的操作,按下Control+D激活Softice,敲入指令VM。我們看到Softice輸出?
的結??
果是一樣的。也就是說盡??
???
??管有多個Windows應用程序在運行,可是系統中只存在一個VM,這個VM就是?
System?VM??
。??
???
???
??按Control+D返回Windows桌面,這時,從“開始選單”中運行“MS-DOS方式”?
,按??
下Control+D激活??
???
??Softice,然后敲入指令:??
???
??:vm??
???
???
??VM?Handle?Status?High?Addr?VM?ID?Client?Regs??
???
??C8D200E8?00000802?C8C00000?00000002?C0F5FF70??
???
??C39200E8?00005A62?C3800000?00000001?C0F06F70??
???
???
??從Softice的輸出可以看到這時系統中存在兩個VM,其中一個就是我們剛才看到?
的??
???
??System?VM(VM?ID=1),另外,又多了一個ID=2的VM,這個VM就是DOS?VM,??
???
??也就是說剛才的那個“MS-DOS方式”就是運行在這個DOS?VM中的。??
???
???
??按Control+D返回Windows桌面,從“開始選單”中再運行幾個“MS-DOS方式”?
??
???
??,按下Control+D激活Softice,敲入VM指令,你會發現VM增多了,其數量等于?
所??
???
??有的“MS-DOS方式”的數目加1。??
???
???
??現在您信了吧??所有的DOS應用程序都是運行在各自的DOS?VM中,而所有的??
???
??Windows?應用程序都運行在同一個System?VM中。這是非常重要的概念。??
???
???
???
???
???
******************************************?
**??
***************************??
???
??VxD世界——Windows的保護模式??
???
???
??一般來說,80x86(80386及其以后的各代CPU)可以在三種模式下運轉:實模式?
,??
???
??保護模式,V86模式。實模式就是古老的MS-DOS的運行環境。Win95只利用了兩?
??
???
??種模式:保護模式和V86模式。??
???
???
??為什么要進入保護模式??
???
??保護模式有許多優越性。其中最最直接的好處就是:你的程序可以利用更多的內?
存了??
!??
???
???
??不要以為這是什么大不了的問題,我相信每一個曾在MS-DOS下寫程序的人都有?
一??
???
??個苦惱:怎樣在程序中開個足夠大的數組?動不動就會堆棧溢出,許多事都不能?
做??
???
??了。不要怨Turbo?C、MS?Fortran、Turbo?Pascal,它們也是心有余而力不足。?
這些??
???
???
??煩惱都源自“你的程序是運行在實模式下的”。運行在實模式下的16位程序最多?
只??
???
??能存取1M的內存。你也許會問:我的機器上不是有64M內存嗎?是啊,如果說你?
是??
???
??在MS-DOS下運行程序(或者說CPU運轉在實模式下),那你只利用了1M內存,??
?
???
??其余的內存都“下崗”了,在這種情況下,你的386/486/586/PⅡ只相當于一個?
跑得??
???
???
??快的8086。??
???
???
??但是保護模式給了我們一個驚喜。理論上,在保護模式下,CPU可以尋址4096M(?
??
???
??即4GB)內存。這就是說,只需把你的程序編譯成32位的可執行程序(當然得借?
助??
???
??32位編譯器),你就可以在程序中充分利用內存了,這樣做的直接結果是:你可?
以??
???
??不用再為堆棧溢出或開不出5000×5000的數組而吃不下飯了。??
???
???
??正是4GB內存存取的實現,使得操作系統有了更加智能化的物質基礎,多任務的?
實??
???
??現才可以提到日程上來考慮了。??
???
???
??再深入一些??
???
???
??從硬件結構上說,386由三個寄存器CR0、CR1、CR2控制著CPU的運轉。比如說??
???
??,CR0的第0位就是用來判斷當前CPU是工作在保護模式還是實模式下。學過??
???
??8088/8086匯編語言的人一定熟悉AX、BX、CX、DX、SI、DI、SP、BP這些16位??
???
??的寄存器,在80386中,這些寄存器被擴展到了32位,即EAX、EBX、ECX、EDX??
???
??、ESI、EDI、ESP、EBP,如果CPU是運轉在實模式下,那你只能利用這些32位寄?
??
???
??存器的前16位,而后面的16位就浪費了。??
???
???
??段的概念是我們理解保護模式的關鍵所在。在實模式下,段寄存器中存放著16位?
的??
???
??段地址,這時,段地址是參與尋址的:把段地址左移4位,加上偏移地址,就是?
20位??
???
???
??的物理地址了。在保護模式下,段寄存器中存放著16位的段選擇器(Segment??
???
??Selector),這個值是不直接參與尋址的,而只是一個指向段描述表(?
Segment??
???
??Descriptor?Table)的索引。段描述表(Segment?Descriptor?Table)中存放著?
段描??
???
???
??述符(Segment?Descriptor)。段描述符中有關于段的描述,比如:段在內存中?
的??
???
??位置、段的大小、段的類型(是數據段還是代碼段)等等。??
???
???
??當CPU運行在保護模式下時,內存中往往有至少三張段描述表:全局描述表(??
???
??Global?Descriptor?Table,簡稱GDT)、局部描述表(Local?Descriptor,簡稱?
LDT)??
???
???
??、中斷描述表(Interrupt?Descriptor?Table,簡稱IDT)。說到這里,我想提?
醒讀者??
???
???
??注意:記住GDT、LDT、IDT這三個詞的含義,我們在后面會經常用到。??
???
???
??段描述表不可能超過64K(為什么?如果回答不上來,那就再看看前面的講解)?
,??
???
??每個段描述符(也就是段描述表中的一項)都是8byte長,所以說,每個段描述?
表最??
???
???
??多只能包含8192個段描述符。??
???
???
??在今后的“走進VxD世界”中,我們將對段描述表、段描述符以及分頁機制作進?
一??
???
??步的講解。??
???
???
???
???
*************************?
**??
***************************??
???
??VxD世界——關于“描述表”??
???
???
??前面我們提到了在保護模式下,內存中往往至少有三張表:GDT,LDT,IDT。聰?
明??
???
??的你可能要問:這幾張表都在內存的什么地方呢???
???
???
??圖1?幾個重要的寄存器的示意圖??
???
???
??這三張表的位置是由三個寄存器記錄的。這三個寄存器分別是:GDTR,LDTR,??
?
???
??IDTR。我們還要補充講解一個寄存器,那就是TR(Task?Register),這個寄存?
器??
???
??與保護模式的任務管理有關。在386中,這幾個寄存器如圖1所示。??
???
???
??我們可以看到GDTR和IDTR都分別包含32位的物理地址和16位的權限級別,總共48?
??
???
??位。GDTR和IDTR中的32位地址是線性地址,不是段:偏移(Seg:Offset)的組合?
??
???
??形式,它表明了段開始的地方,如果說系統還沒有啟動內存分頁管理機制的話,?
那??
???
??這個線性地址就是物理地址,可是一旦系統啟動了內存分頁管理機制,GDTR和??
?
???
??IDTR中的32位線性地址就不再指向物理地址了。??
???
???
??CPU保留了GDT中的第一個描述符,任何試圖通過GDT中的第一個描述符來訪問內?
??
???
??存的操作都是非法的(還記得Win95下那可怕的藍屏嗎?)。如果指向GDT的段選?
??
???
??擇器的Index域為0的話,那就指向空的段選擇器。段選擇器的示意如圖2:??
???
???
??TI:Talbe?Indicator??
???
??RPL:Requestor?Privilege?Level??
???
???
??圖2?段選擇器??
???
???
??這就是說,在保護模式下,far?NULL指針是非法的。而在實模式下,NULL指針卻?
是有??
意義的。??
???
???
??在內存中(當然是指CPU工作在保護模式下啦),GDT和IDT都只有一份,也就是?
??
???
??說,它們是全局的,任何一個任務改變了這兩張表,都會對別的任務產生影響。?
??
???
???
??下面我們談談IDT、IDT中的每一項,也就是每一個描述符,都定義了256個中斷?
中??
???
??的一個。還記得實模式下MS-DOS環境中的中斷向量表吧?在保護模式下,中斷?
描??
???
??述表IDT代替了中斷向量表。雖說中斷描述表可以容納8192個中斷描述符,可是?
??
???
??CPU能利用的只有處于前面的256個。所以中斷描述表的長度限制應該是7FFh(23?
??
???
??×28-1)。??
???
???
??T=0:Interrupt?gate描述符??
???
??1:Trap?gate描述符??
???
???
??圖3?Trap/Interrupt?gate描述符??
???
???
??其實中斷描述表(IDT)中可以有兩種描述符:Interrupt?gate描述符、Trap??
gate描??
???
???
??述符。圖3顯示了Trap/Interrupt?gate描述符的結構。這里提到了gate這個詞,?
一般??
???
???
??譯作“門”。?“中斷門”形像地直接表示了中斷調用的過程:中斷調用就像經?
過一??
???
???
??扇門一樣,這個門就是中斷描述符,因為中斷描述符中有DPL等權限盤查的標志?
,??
???
??所以要想通過這扇門調用相應的中斷服務程序是需要一定的資格的。??
???
???
??Trap和Interrupt?gate非常相似,一般來說Trap?gate是用來捕獲系統異常,而?
??
???
??Interrupt?gate用來響應中斷。在具體的實現上,只有一點不同:Interrupt??
gate會??
將??
???
??IF置為0,這樣可以屏蔽硬件中斷。但是Trap?gate不會改變IF的值。??
???
???
??寄存器LDTR中存有LDT的位置。與GDT不同的是,內存中可以有多份LDT。每一個?
??
???
??任務都可以有自己的LDT。從圖1中我們可以看到,LDTR不包含“地址?/?權限”?
位??
???
??。LDTR中所包含的是一個段選擇器。這個段選擇器指向GDT中的一項,但不是普?
??
???
??通的一項,這一項是指向某一LDT的描述符。你可能馬上意識到,GDT中可以包含?
??
???
??指向不同LDT的描述符,不錯,正是這樣的。在Windows保護模式下,每一個MS-?
??
???
??DOS應用程序都有自己的LDT,而所有的Windows應用程序都共享一份LDT。是不??
?
???
??是想起些什么來了?對了,這與Windows中VM(虛擬機)的概念多少類似!??
???
???
???
???
???
**********************************
**??
***************************??
???
??VxD世界——分頁機制??
???
???
??關于分頁機制??
???
???
??在這種機制下,內存被劃分為固定長度的“頁面”。在保護模式下,“頁面”是?
受??
???
??到保護的,并可以被“虛擬”(說穿了,“虛擬”的東西就是說,本來沒有的,?
而??
???
??應用程序卻誤以為有。比如說,你只有64MB內存,而你的程序卻傻乎乎地認為它?
可??
???
??以有4GB的內存用,這就是“虛擬”)。??
???
???
??還記得前面講過的保護模式下“段”的概念嗎?在保護模式下,段的長度是可以?
變??
???
??化的,而這里,“頁面”的大小是不能變的,雖然它倆都受到保護模式的“保護?
”??
???
??和“虛擬”。那么“頁面”的大小是多少呢?答案是4KB。??
???
???
??假如現在有個32位的線性地址,我們來看一下怎么由這個線性地址獲得物理地址?
。??
???
???
??圖1?線性地址通過頁面映射為物理地址??
???
???
??請記住圖1表示內容,因為它實在是太重要了。圖中的CR3是指寄存器CR3的值。?
如??
???
??果你裝了Softice?for?Win95,那就按下Ctrl+D激活Softice,然后敲指令:??
???
???
??CPU;這時會看到CR3的值。??
???
???
??線性地址轉換為物理地址的例子??
???
???
??假設現有線性地址8000DD88h,我們來看一下它到底指向何處物理地址。性線地?
址??
???
??8000DD88h應作如下解析:??
???
???
??800?0D?D88??
???
??Page?Table?Index?Page?Index?Page?Offset??
???
??(頁面表索引)?(頁面索引)?(頁面偏移地址)??
???
???
??現在我們需要知道頁面表目錄的起始地址。于是我們查看寄存器CR3。假設寄存?
器??
???
??CR3=891000h,那么891000h?+?200h?4?=?891800h(想一想為什么要?4,答案?
??
???
??在文章后注釋[1]處),現在我們要查看一下線性地址891800h處的值,在?
Softice中??
???
???
??,敲如下的指令:??
???
???
??:?d?891800??
???
???
??假設得到的是493227h,這個值與0FFFFF000h作“與”運算,就得到了我們要找?
??
???
??的Page?Table的起始物理地址493000h,那么493000h?+?4?0Dh?=?49302Ch(想?
??
???
??一想為什么要?4,見注釋[2]),然后我們要知道物理地址49302Ch處的值,但?
是在??
???
???
??Softice中,我們無法直接獲得存放在物理地址處的值,只能通過其對應的線性?
地址??
???
???
??來查看。在Softice中,敲如下指令:??
???
???
??:?phys?49302C??
???
???
??假設得到的是線性地址89302Ch(有時你會得到兩個不同的值,我們取第一個值?
。??
???
??想一想為什么會有兩個不同的值?答案在注釋[3]),現在我們查看一下線性地?
址??
???
??89302Ch處的值,這也是物理地址49302Ch處的值。在Softice中,敲如下指令:?
??
???
???
??:?d?89302C??
???
???
??假設得到的是3F5000h,這就是我們要找的Page(頁面)的物理地址。然后,??
???
??3F5000h?+?0D88h?=?3F5D88h,這就是線性地址8000DD88h對應的物理地址。我?
??
???
??們想在Softice中查看物理地址3F5D88h處的值,那就得找到其相應的線性地址。?
在??
???
??Softice中,敲如下指令:??
???
???
??:?phys?3F5D88??
???
???
??假設我們得到線性地址7F5D88h,讓我們看一下這個線性地址7F5D88h處的值。在?
??
???
??softice中,敲如下指令:??
???
???
??:?d?7F5D88??
???
???
??讓我們記下結果,然后再看一下線性地址8000DD88h處的值。??
???
???
??:?d?8000DD88??
???
???
??你會發現線性地址7F5D88h與線性地址8000DD88h所指向的值是完全一樣的。??
???
???
??一般來說,為了提高地址轉換的效率,在CPU里都會有一個頁面轉換緩沖區(TLB?
??
???
??),里面存放著最近頁面轉換的信息。??
???
???
??MMU(Memory?Management?Unit)??
???
???
??從386開始,CPU都帶有一個內存管理單元(Memory?Management?Unit,簡稱??
???
??MMU)。??
???
???
??MMU負責提供的功能:虛擬內存、重組段、進程分隔、頁面保護、地址轉換。??
???
???
??我們在上面的例子中所進行的線性地址到物理地址的轉換就是由MMU來完成的。?
??
???
???
??模式轉換??
???
???
??我們簡單提一下保護模式與實模式之間的切換過程,有個概念就可以了。??
???
???
??由實模式切換到保護模式:檢測一下當前CPU是否有能力運行于保護模式下;檢?
測??
???
??保護模式環境(DPMI或VCPI);建立IDT;建立GDT;禁止中斷,包括NMI;加載?
??
???
??GDTR;設置IDTR;設置CR0的bit?0;清空指令隊列;加載段寄存器;允許中斷。?
??
???
???
??由保護模式切換到實模式:禁止中斷,包括NMI;禁止頁面轉換;設置數據段寄?
存??
???
??器的值為準實模式下的選擇器;重置CR0的bit?0;清空指令隊列;設置?
IDTR=0000??
???
??:03FF;允許中斷。??
???
???
??[1]因為在Page?Table?Directory中,每一個表項占4個字節。??
???
???
??[2]因為在Page?Idex?Table中,每一個表項占4個字節。??
???
???
??[3]因為線性地址到物理地址的映射關系不是一對一的,這就是說同一處物理地?
址,??
???
???
??可能有多處線性地址指向它。??
???
???
???
???
???
???
********************************?
**??
***************************??
???
??VxD世界——Win95?的線性地址分配??
???
???
??圖1是一張描述Win95線性地址空間的圖。下面我們對這張圖加以詳細說明。??
???
???
??圖1?Windows?95線性地址分配圖??
???
???
??0~4MB:??
???
???
??這部分在圖上標的是DOS內存區,其實這是不確切的。我們知道16位的DOS應用程?
??
???
??序只能存取0~1MB的內存空間,那為什么還要把1MB~4MB的3MB內存也算作??
???
??DOS內存區呢?答案就在我們前面講過的分頁機制中。我們再溫習一下:一個頁?
面??
???
??(Page)是4kB,一個頁面表(Page?Talbe)有1024個頁面,一個頁面表目錄(?
??
???
??Page?Table?Directory)有1024個頁面表。那么一個頁面表目錄項就可以映射?
1024×??
???
???
??4k=4MB的線性地址。其實DOS只能利用到0MB~1MB的內存空間,那1MB~4MB??
???
??的地址空間留給誰了呢?關于這個問題,筆者曾經問過Karen?Hazzah、Walter??
?
???
??Oney和Geoff?Chappell,他們的回答是:這一部分是空的。Win95為了圖省事,?
就??
???
??把1MB~4MB的線性地址空間也當作DOS內存區,這樣Win95在DOS?VM之間切換??
???
??時,就可以頁面表目錄項(Page?Table?Directory?Entry)為單位來進行。這樣?
雖說??
???
???
??浪費了3MB的地址,卻換來了DOS?VM切換的高效率。??
???
???
??那圖1中標出的①又是指的什么呢?呵呵,Win95有趣得很,為了使系統、Win16?
應??
???
??用程序能與DOS應用程序互相協作,于是在0~1MB之間,其實是緊挨著1MB的下??
?
???
??面,放了一個Win16全局堆(其實是Win16全局堆很小的一部分)。說到這里,筆?
者??
???
??想起了一個深受大家喜愛的DOS下的編輯器Quick?Edit?4.0,這個編輯器有一個?
非常??
???
???
??有趣的功能:能與Windows共享剪貼板。當時我們猜想它一定用到了未公開的?
DPMI??
???
??調用,現在從圖1來看,肯定是①部分的Win16全局堆幫了它的忙啦。??
???
???
??同時請注意圖1中還有一個②,這部分我們稱作Win16全局堆的高端部分。為什么?
要??
???
??在這里安置一個Win16的全局堆?它是用來作什么的呢???
???
???
??這個問題的答案是:為了高效率地切換DOS?VM。??
???
???
??每一個DOS?VM在大于3GB的地址空間都有一個備份,Win95在DOS?VM之間進行??
???
??切換時,只是簡單切換一下頁面表目錄的第一項就可以了。所以說,如果一個?
VxD??
???
??想訪問某個DOS?VM,沒有必要一定要等到該DOS?VM成為當前VM才能訪問,它可??
?
???
??以直接去②訪問那個DOS?VM的備份。這個DOS?VM備份的地址我們稱作High-??
???
??linear?address。??
???
???
??后面的文章中,我們將詳細講到如何在VxD中訪問DOS?VM。??
???
???
???
???
???
***********************?
**??
***************************??
???
??VxD世界——Win95?內存揭秘??
???
???
??上期“走進VxD世界”中我們談到了Win95中0~4MB線性內存空間分配情況。下面?
??
???
??我們接著講余下的4MB~4GB線性內存空間的分配。??
???
???
??4MB~2GB??
???
??Win32應用程序的代碼、數據和資源都存放在這段內存中了,這部分內存,對于?
每??
???
??個Win32應用程序來說都是私有的。這里是最能體現保護模式分頁機制作用的地?
方??
???
??。兩個Win32應用程序,對相同的線性地址(4MB~2GB范圍內)進行讀寫,實際?
??
???
??上,它們是在對不同的物理地址進行讀寫。讓我們算一下,這段內存對應多少個?
??
???
??Page?Directory?Entry。我們知道一個Page?Directory?Entry對應4MB線性內存?
,那??
???
???
??4MB~2GB的內存就對應于1024?/?2?-?1?=?511個Page?Directory?Entry。也就?
是說??
???
???
??Win95通過操縱這511個Page?Directory?Entry實現了Win32應用程序“獨立”的?
線性??
???
???
??地址空間。打個比方來說吧,現在有511個抽屜,上帝告訴A說:這些抽屜里都是?
金??
???
??幣,同時告訴B說:這些抽屜里都是銀幣。并規定只有上帝能打開抽屜。其實抽?
屜里??
???
???
??可能只有一枚銅板,也可能什么都沒有。這時,A想看看某個抽屜里到底是不是?
金幣??
???
???
??,于是上帝就背地里臨時往那個抽屜中放一個金幣,然后打開抽屜讓A看,于是?
A就??
???
??信了。這個伎倆同樣作用于B,B也相信了那511個抽屜里都是他想要的銀幣。保?
護??
???
??模式下的操作系統(這里當然指Win95)就相當于上帝,而被騙的A和B就相當于?
運??
???
??行于保護模式下的Win32應用程序。那只操縱抽屜的上帝之手就是分頁機制。??
???
???
??2GB~3GB??
???
??這部分內存空間我們稱之為“應用程序共享內存區”,這里存放著Ring?3級應用?
程??
???
??序需要共享的數據和代碼。其中包括Win95系統DLL(如User32.dll,Kernel32.?
dll等??
???
???
??)、內存映射文件、Win16應用程序以及DPMI調用分配的內存。??
???
???
??通過把要共享的數據映射到2GB~3GB之間的線性內存空間,可以實現Win32應用?
??
???
??程序間的數據共享。??
???
???
??Win16應用程序是需要共享線性地址空間的,這是Windows?3.1的歷史遺留問題。?
為??
???
??了使以前運行于Windows?3.1的Win16應用程序能在Win95下有同樣的運行效果,?
于??
???
??是Microsoft決定把Win16應用程序放到這段共享內存區來運行。應該說這是比較?
合??
???
??理的決策:既省時省力,又保證了對上一代產品的良好兼容性。??
???
???
??再從分頁機制的角度上來思考一下這段“共享內存區”是如何實現的。2GB~3GB?
??
???
??的線性空間對應著256個Page?Directory?Entry。無論誰在運行,Win95都不會改?
變這??
???
???
??256個Page?Directory?Entry,也就是說2GB~3GB的線性地址空間對應的物理地?
址??
???
??是一樣的。這樣,Win95什么也不用做就實現了2GB~3GB線性地址空間的內存共?
??
???
??享。??
???
???
??3GB~4GB??
???
??這部分內存空間稱為“系統內存區”。只有Ring?0級的VMM和VxD可以訪問這部分?
??
???
??內存空間。這部分內存也是共享的。雖說Ring?3的應用程序無法直接共享這部分?
內??
???
??存空間(也就是說SDK中講述的方法無法做到),但是我們還是稱之為共享內存?
區??
???
??,至少從分頁機制的角度上說,對應于這部分內存的Page?Directory?Entry是不?
變的??
???
???
??。其實Win32應用程序還是有辦法訪問這部分內存空間的。一般作法是,在VxD中?
分??
???
??配一塊內存,然后把指向那塊內存的32位地址指針傳給Win32應用程序,這樣就?
可??
???
??以在Win32應用程序中直接訪問那塊內存了。前面我們在講0~4MB內存空間時,?
提??
???
??到High-linear?address,即DOS?VM備份的地方,就在3GB~4GB內存空間中。??
?
???
???
??對于Windows應用程序開發者來說,實現內存共享有時是非常重要的。對于VxD開?
??
???
??發者來說,還應注意,對于經常需要存取的共享內存頁面,必須調用VMM的??
???
??_LinPageLock服務進行鎖定,否則會出現Out-Of-Context?Memory?Reference?
。??
???
???
???
???
********************?
**??
***************************??
???
??VxD世界——硬件虛擬與虛擬設備驅動程序??
???
???
??·硬件虛擬·??
???
???
?
??回憶一下,在實模式DOS下,實模式的MS-DOS應用程序調用runtime?library中?
的??
???
??fgets或—kbhit函數,這些函數就會直接通過軟中斷int?21h調用MS-DOS服務(?
MS??
???
??-DOS服務會最終通過調用軟中斷int?16h調用BIOS服務),或者通過軟中斷?
int?16h??
???
???
??調用BIOS服務。BIOS通過IN?/?OUT指令來直接操縱鍵盤或中斷控制器。??
???
???
??我們通過下面這張圖來理解一下什么是硬件虛擬的實現(見圖1)。??
???
???
??兩個不同的MS-DOS應用程序可能要同時訪問鍵盤,它們都感到自己在直接操縱?
著??
???
??硬件。其實從全局看,這兩個MS-DOS應用程序對鍵盤的訪問被VKD串行化了。??
?
???
??這兩上MS-DOS應用程序其實是在操縱“虛擬的硬件”。??
???
???
??硬件虛擬的一個很關鍵的基礎是:80386芯片的“port?trapping”功能,這使得?
VKD??
???
???
??可以捕獲ring?3應用程序對鍵盤的訪問。我們想起前面講保護模式的內存管理時?
,提??
???
???
??到“虛擬內存”的概念,其時“虛擬內存”的實現也是因為80386芯片具有“??
???
??paging?trap?”功能。??
???
???
??·虛擬設備驅動程序·??
???
???
??Windows系統中,是VMM和VxDs實現了硬件虛擬(VMM本身就是一些VxD的集合??
???
??)。在Win95中,有兩種VxD:static?VxD(靜態加載的VxD)和dynamic?VxD(動?
??
???
??態加載的VxD)。在Windows?3.1中,只有一種VxD:static?VxD。Static?VxD的?
加載??
???
???
??需要把VxD放在SYSTEM.INI或注冊表中。比如說,你寫了一個文件名為Fool.VxD?
的??
???
??static?VxD,那么你可以在SYSTEM.INI中的如下位置加上一句:??
???
???
??……??
???
??[386Enh]??
???
??device=Fool.VxD??
???
??……??
???
???
??或是在注冊表的如下位置加入如下一項:??
???
??\HKEY—LOCAL—MACHINE\System\CurrentControlSet\services\VxD\Fool.VxD??
?
???
???
??這樣Win95在啟動時就會自動加載Fool.VxD。??
???
??相對于Windows?3.1而言,Win95又增加了dynamic?VxD(動態加載的VxD)。在??
?
???
??Win95中,主要操縱dynamic?VxD的是configuration?Manager和Input/Output??
???
??Supervisor這兩個功能模塊(這兩個模塊自己卻是static?VxD)。??
???
?
???
??圖1?鍵盤的虛擬??
???
???
??VKD:Virtual?keyboard?device?VPICD:Virtual?PIC?device??
???
???
???
???
???
*****************************??
***************************??
???
??VxD世界——VxD文件格式??
???
???
?
??我們知道,MS-DOS下可執行文件.EXE是MZ格式,也就是說.EXE文件的前兩個??
???
??字節是字符串“MZ”。而Windows?3.1的.EXE是NE(New?Executable)格式,??
???
??Win95和WinNT的.EXE是PE(Portable?Executable)格式,VxD則是LE(Linear??
?
???
??Executable)格式。但是有一點需要注意,在NE、PE和LE的頭部,總嵌有一小段?
??
???
??DOS程序,它的作用是:當你在DOS下運行這幾種.EXE文件時,它會提示你“This?
??
???
??program?cannot?be?run?in?DOS?mode”。??
???
???
??DEBUG?TEST.VXD??
???
???
??LE文件格式最早出自OS/2?2.0。這種格式的文件可以同時包含16位和32位代碼,?
這??
???
??正是VxD需要的,因為VxD在加載的初始化階段,需要進行一些實模式的操作,這?
??
???
??需要16位代碼,而VxD的主要運行階段是在32位環境中,這又需要32位代碼,所?
以??
???
??LE文件格式正好適合于VxD。??
???
???
??VxD不僅有16位和32位兩種代碼,而且,它把數據段和代碼段攪和在一起,只是?
通??
???
??過段前的標識來表明該段在運行時的特性。VxD之所以這樣,是因為VxD所用的?
Flat??
???
??mode的代碼和Data?selector有同樣的基本地址和限制,這樣當VxD想訪問數據或?
代??
???
??碼時,用哪個段寄存器都可以。VxD中常用的Segment?Class見表1。??
???
???
??在VxD中,LCODE、PCODE和PDATA段包含了主要的數據和代碼。LCODE段所包??
???
??含的數據和代碼必須總在內存中,我們在VxD中處理硬件中斷的代碼和相關數據?
必??
???
??須位于LCODE段中,否則,在處理硬件中斷時就會出現可怕的Page?fault。??
???
???
??ICODE段包含的是VxD初始化時要完成的工作,當VxD完成初始后,ICODE段中的??
?
???
??代碼和數據將被VMM拋棄。??
???
???
??RCODE中包含的是16位代碼和數據,用作實模式初始化階段。??
???
???
??SCODE中包含Static?Code和Data,一般來說,SCODE對于動態加載的VxD尤其有??
?
???
??用。試想一下,如果可動態加載的VxD包含了一個回調函數,當你卸載這個VxD后?
??
???
??,又需要這個回調函數繼續發生作用,那你就得把這個回調函數放到SCODE中。?
再??
???
??者,如果你需要知道某個動態加載的VxD被加、卸載了幾次,那可以在SCODE中放?
??
???
??個記數器,每次該VxD被加載時都把該記數器加一。??
???
???
??由于VxD的文件格式比較特殊,所以你必須使用可以產生LE格式的鏈接器(?
Linker??
???
??)。如果你要開發Windows?3.1的VxD,那得用Windows?3.1?DDK帶的鏈接器。但?
是??
???
??如果開發Win95的VxD,那用MSVC?2.0及其以后版本的鏈接器就可以了。有一點需?
??
???
??要注意,MSVC?4.1的鏈接器由于存在一些小BUG,不能用于生成VxD。??
???
???
??表1??
???
??Segment?Class?描?述??
???
??LCODE?Page-locked?code?and?data??
???
??PCODE?Pageable?code??
???
??PDATA?Pageable?data??
???
??ICODE?Initialization-only?code?and?data??
???
??SCODE?Static?code?and?data??
???
??RCODE?Real-mode?initialization??
???
???
???
???
???
???
**********************************??
***************************??
???
??VxD世界——VxD開發的利器SoftIce/VToolsD??
???
???
??SoftIce的安裝??
???
???
??對于從事Windows系統開發的人來說,SoftIce是必不可少的利器。目前SoftIce?
的最??
???
???
??新版本是3.24,有Win?95的版本,也有Win?NT的版本。SoftIce?3.24?for?Win??
95可以??
???
???
?
??從國內的一些FTP站下載。??
???
???
??在SoftIce的安裝過程中,有一步是很重要的,那就是對顯卡的測試。新版本的?
??
???
??SoftIce提供對更多種顯卡的支持。如果說顯卡不被SoftIce支持,那就意味著??
?
???
??SoftIce將無法正常工作。??
???
???
??在安裝過程中,如果Test通不過,那就試著選一下Universal?Video?Driver或者?
Use??
???
???
??monochrome?card/monitor。如果還通不過的話,那就在Display?Adapter??
Selection??
???
???
??列表框中選擇Stand?VGA再試。如果還不行的話,那就試著去下載一份new??
SoftIce??
???
??video?driver(在國內的FTP站上也可以找到),如果運氣好的話,你的顯卡會?
被??
???
??SoftIce支持。??
???
???
??安裝過程結束后,重新啟動計算機,按下Ctrl+D進入SoftIce,如果SoftIce能?
正常??
???
???
??工作,那我們的安裝就成功了。你可以敲入help來看一下SoftIce的簡要幫助,?
或者??
???
???
??,按下Ctrl+D返回Windows桌面。??
???
???
??VToolsD的安裝??
???
???
??在VToolsD出世之前,VxD的開發者面對DDK浩如煙海的古怪的asm代碼,能忍受下?
??
???
??來的人不多。VToolsD就是把幸福帶給VxD開發者的天使。就憑這一點,VToolsD?
就??
???
??令VxD開發者趨之若鶩。VToolsD是Vireo公司的作品,目前國內的FTP站上有??
???
??VToolsD?2.03?for?Win95下載(如果運氣好的話,還可以找到2.04、2.05b)。?
從國??
???
???
??內FTP站下載的VToolsD在安裝時有一些需要注意的地方。??
???
???
??首先,在安裝過程中會遇到對話框,詢問你是否需要MASM6.11c。VToolsD并不包?
??
???
??含MASM?6.11c,但是,可以從DDK?for?Win95中找到MASM?6.11c。當你的程序中?
??
???
??需要嵌入匯編代碼時,MASM?6.11c就不可缺少了(如果你只用C語言開發VxD,那?
??
???
??就用不著了)。??
???
???
??圖1所示是對調試器的選擇,請選擇SoftIce。??
???
???
??圖1?調制器的選擇??
???
???
??在SoftIce的路徑設置對話筐中,請選擇SoftIce的Util16子目錄。??
???
???
??再者,在安裝過程中,圖2所示的兩個選項是不能選的,否則,安裝過程將無法?
正常結??
束。??
???
???
??圖2?不要選擇的兩個選項??
???
???
??在VToolsD安裝完成之后,重新啟動計算機,然后,進到VToolsD安裝目錄下的??
?
???
??examples\c\simple\下,敲如下的命令:??
???
???
??nmake-f?simple.mak??
???
???
??如果一切正常的話,將生成simple.vxd。??
???
???
??如果不行的話,那就在DOS提示符下敲set命令,檢查一下環境變量的設置。下面?
是??
???
??我的系統中相應環境變量的設置,你需要根據自己系統的實際情況調整一下路徑?
設置??
:??
???
???
??VTOOLSD=E:\VTD95??
???
??PATH=?%PAH%;C:\MSDEV\BIN;?E:\VTD95\BIN??
???
??INCLUDE=C:\MSDEV\INCLUDE;?E:\VTD95\INCLUDE??
???
??LIB=C:\MSDEV\LIB;E:\VTD95\LIB??
???
???
??把這些環境變量的設置加到autoexec.bat中去,以使其每次開機都自動設置。??
?
???
???
???
???
???
*********************************?
**??
*******************************??
???
??VxD世界——用VToolsD開發一個簡單的VxD??
???
???
??這一次,我們講一下如何用VToolsD開發一個最簡單的VxD,以及用SoftIce進行?
源程序??
級的調試。??
???
???
??VToolsD的使用??
???
???
??在VtoolsD中,有一個最重要的VxD開發工具:QuickVxD。QuickVxD可以為我們自?
??
???
??動生成VxD源程序框架,而且QuickVxD提供了許多VxD的特性選項,例如可以選擇?
??
???
??要生成的VxD是動態加載的或是靜態加載的,要使用的編程語言是C還是C++等?
等。??
???
???
???
??我們要利用QuickVxD自動生成的是一個可動態加載的、基于C語言的VxD框架。之?
??
???
??所以選用動態加載的VxD,是為了調試VxD的方便。每次修改代碼,重新編譯連接?
??
???
??之后,要使VxD重新生效,如果采用靜態加載的VxD,那就不得不重新啟動電腦,?
??
???
??而若采用了動態加載的VxD,那只須使用VToolsD帶的另一個開發工具VxDLoad就?
??
???
??可以卸出或重新加載內存中的VxD。之所以采用C語言而不是C++,是因為其簡?
潔??
???
??易懂。請按照如圖1~圖4進行選擇。按下Generate?Now按鈕,我們就獲得了動態?
加??
???
??載的、基于C語言的VxD的源程序。??
???
???
??如果您是按照上一篇文章中講過的VToolsD的編譯環境設置系統,那我們就可以?
編??
???
??譯剛才生成的這個最簡單的VxD了。在DOS提示符下輸入指令:??
???
???
??nmake?-f?myfirst.mak??
???
???
??看一下當前目錄下是否生成了myfirst.vxd,如果有,那我們下面準備對這個?
VxD進行??
???
???
??源程序級的調試。如果沒有,那么很可能是您的編譯環境沒有正確配置,請找來?
上??
???
??一篇文章好好讀讀。??
???
???
??用VxDLoad加載myfirst.vxd(見圖5)??
???
???
??按下Load按鈕,會出現VxD?load?successfully消息框。??
???
???
??用SoftIce調試VxD??
???
???
??對于SoftIce選單作如下選擇:??
???
??(1)File→Open?Module選擇我們剛才生成的myfirst.vxd。??
???
??(2)Module→Translate,如果Symbol?Loader提示無法加載一些asm文件,那就?
跳過??
所有的asm文件。??
???
??(3)Module→Load。??
???
???
??按下Ctrl+D,進入SoftIce運行環境中(如果您還沒有按照上一篇文章中安裝??
?
???
??SoftIce的話,那就無法再進行下面的測試)。輸入如下指令:??
???
??:file????
???
???
??myfirst.c??
???
??:file?myfirst.c??
???
???
??這時,在SoftIce中,您將會看到myfirst.c的源程序。??
???
???
??圖1選項頁面之一??
???
??圖2選項頁面之二??
???
??圖3選項頁面之三??
???
??圖4可以生成VxD源程序了??
???
??圖5用VxD?Load加載myfirst.vxd??
???
???
???
???
???
*********************************
**??
*******************************??
???
??VxD世界——VxD的結構??
???
???
??在上一次“走進VxD”世界中,我們用VToolsD生成了一個最簡單的可以動態加載?
的??
???
??VxD——MYFIST程序。我們以這個例子為基礎,不斷地豐富其功能,并以此講解?
一些V??
xD的基本技術。??
???
??下面是MYFIRST主要組成之一:MYFIRST.C。??
???
???
??//?MYFIRST.c?-?main?module?for?VxD?MYFIRST??
???
??#define?DEVICE_MAIN??
???
??#include?"myfirst.h"??
???
??#undef?DEVICE_MAIN??
???
??Declare_Virtual_Device(MYFIRST)??
???
??VOID_cdecl?V86_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs)?{?}??
???
??VOID?_cdecl?PM_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs)?{?}??
???
???
??DefineControlHandler(SYS_DYNAMIC_DEVICE_INIT,??
???
??OnSysDynamicDeviceInit);??
???
???
??DefineControlHandler(SYS_DYNAMIC_DEVICE_EXIT,??
???
??OnSysDynamicDeviceExit);??
???
???
??DefineControlHandler(W32_DEVICEIOCONTROL,?OnW32Deviceiocontrol);??
???
?
???
??BOOL?_cdecl?ControlDispatcher(??
???
???DWORD?dwControlMessage,??
???
???DWORD?EBX,?DWORD?EDX,??
???
???DWORD?ESI,?DWORD?EDI,?DWORD?ECX)??
???
???{?START_CONTROL_DISPATCH??
???
????ON_SYS_DYNAMIC_DEVICE_INIT(OnSysDynamicDeviceInit);??
???
????ON_SYS_DYNAMIC_DEVICE_EXIT(OnSysDynamicDeviceExit);??
???
????ON_W32_DEVICEIOCONTROL(OnW32Deviceiocontrol);??
???
???END_CONTROL_DISPATCH??
???
???return?TRUE;}??
???
???
??BOOL?OnSysDynamicDeviceInit()??
???
??{?return?TRUE;?}??
???
??BOOL?OnSysDynamicDeviceExit()??
???
??{?return?TRUE;?}??
???
???
??DWORD?OnW32Deviceiocontrol(PIOCTLPARAMS?p)??
???
??{?return?0;?}??
???
???
??記得在前面的文章中提到過,VxD可以與應用程序實現相互通信。我們在用??
???
??QuickVxD生成這個例子時,又選中了支持動態加載和Real/V86?Mode?API及??
???
??Protected?Mode?API等選項。上面程序中,函數V86_Api_Handler用來實現VxD與?
??
???
??16位的DOS應用程序通信,函數PM_Api_Handler用來實現VxD與16位的Windows??
???
??應用程序或DOS-Extended(DPMI)應用程序通信,函數OnW32Deviceiocontrol用?
來??
???
??實現VxD與32位的Windows應用程序通信。函數OnSysDynamicDeviceInit和??
???
??OnSysDynamicDeviceExit自然是用來控制VxD動態加載和卸載啦。??
???
???
??上面的代碼中有兩個宏DefineControlHandler和ControlDispatcher,用來把這?
些函數??
???
???
??與VxD的消息機制聯系起來。好像我們搞清楚了,不,再仔細看一下,宏??
???
??DefineControlHandler和ControlDispatcher都只是定義了三個函數??
???
??OnW32Deviceiocontrol、OnSysDynamicDeviceInit和OnSysDynamicDeviceExit的?
消??
???
??息映射關系。我們很自然地想到,函數V86_Api_Handler和PM_Api_Handler呢??
???
??,為什么能肯定VxD一定用這兩個函數與16位應用程序通信呢???
???
???
??讓我們在VToolsD的include子目錄下找一找,我們會發現VToolsC.h中有這兩個?
函數??
???
???
??的定義。下面的代碼摘自VToolsC.h。??
???
???
??#define?Declare_Virtual_Device_Ex(VName,?RefData)?\??
???
???
??extern?_C_?void?_cdecl?V86_Api_Handler(VMHANDLE?hVM,?PCLIENT_??
???
??STRUCT?pRegs);?\??
???
??extern?_C_?void?_cdecl?PM_Api_Handler(VMHANDLE?hVM,?PCLIENT_??
???
??STRUCT?pRegs);?\??
???
??extern?_C_?void?(?VXD_SERVICE_TABLE[])();?\??
???
??_EXC_?DDB?The_DDB?=?{?0,?DDK_VERSION,?VName##_DeviceID,?VName??
???
??##_Major,?\??
???
??VName##_Minor,?0,?{′?′,′?′,′?′,′?′,′?′,′?′,′?′,′?′},?
?\??
???
??VName##_Init_Order,?(DWORD)?LocalControlDispatcher,?\??
???
??(DWORD)?LocalV86handler,?\??
???
??(DWORD)?LocalPMhandler,?0,?0,?RefData,?(DWORD)?VXD_SERVICE_TABLE,?\??
???
??0,?\??
???
??0,?\??
???
??_SIG_}?;??
???
???
??//?This?is?the?standard?macro?for?declaring?a?DDB,?using?all?default??
value??
s.??
???
???
??#define?Declare_Virtual_Device(VName)?Declare_Virtual_Device_??
???
??Ex(VName,0)??
???
???
??從上面的代碼中,我們可以看到,函數V86_Api_Handler和PM_Api_Handler被??
???
??宏Declare_Virtual_Device聲明已在DDB(Device?Descriptor?Block)中,自然?
不??
???
??用再在MYFIRST.C中進行消息映射了。??
???
???
???
???
???
???
****************************************?
**??
*******************************??
???
??VxD世界__VxD的設備描述塊與VxD?API??
???
???
??VxD設備描述塊??
???
???
??用匯編語言描述MYFIRST.VxD的設備描述塊(DDB?Device?Descriptor?Block)如下?
(??
???
??其實,如果是用DDK來開發VxD,那我們在每個VxD的源程序中都會見到這些代碼?
??
???
??,只是VToolsD替我們封裝了這些費解的東西):??
???
???
??Declare_Virtual_Device?MYFIRST,1,0,MYFIRST_Control,MYFIRST_??
?
???
??Device_ID,MYFIRST_Init_Order,MYFIRST_V86_API_Handler,??
???
??MYFIRST_PM_API_Handler??
???
???
??對于DDB的8個入口來說,只有前面4個是必須的,后面4個的缺省值為0,如果我?
們??
???
??的MYFIRST.VxD不輸出V86?API,那么上面的代碼應這樣寫:??
???
???
??Declare_Virtual_Device?MYFIRST,1,0,MYFIRST_Control,MYFIRST_??
???
??Device_ID,MYFIRST_Init_Order,,MYFIRST_PM_API_Handler??
???
???
??一般來說,MYFIRST_Init_Order是可以設為缺省值0的,因為我們一般不需要特?
??
???
??殊的初始化順序。??
???
???
??你一定會奇怪MYFIRST_Control是怎么回事。讀一下下面的代碼,大概就明白了?
。??
???
???
??BeginProc?MYFIRST_Control??
???
???
??Begin_Control_Dispatch?MYFIRST_Control??
???
???
??Control_Dispatch?Sys_Dynamic_Device_Init,?OnSysDynamicDeviceInit??
???
???
??Control_Dispatch?Sys_Dynamic_Device_Exit,?OnSysDynamicDeviceExit??
???
???
??.........??
???
???
??End_Control_Dispatch?MYFIRST_Control??
???
???
??EndProc?MYFIRST_Control??
???
???
??對比一下VToolsD為我們生成的C程序:??
???
???
??BOOL?_cdecl?ControlDispatcher(??
???
???DWORD?dwControlMessage,??
???
???DWORD?EBX,DWORD?EDX,??
???
???DWORD?ESI,?DWORD?EDI,??
???
???DWORD?ECX)??
???
???{?START_CONTROL_DISPATCH??
???
???ON_SYS_DYNAMIC_DEVICE_INIT(OnSysDynamicDeviceInit);??
???
???ON_SYS_DYNAMIC_DEVICE_EXIT(OnSysDynamicDeviceExit);??
???
???END_CONTROL_DISPATCH??
???
???return?TRUE;}??
???
???
??Windows是基于消息機制的操作系統,這一點在VxD中也體現了出來。MYFIRST_??
?
???
??Control就是接收Windows消息的入口點。Windows發給MYFIRST_Control的消息??
?
???
??與發給Windows應用程序的消息不完全一樣,前者包含了一些系統信息。MYFIRST?
??
???
??_Control在收到消息后,調用相應的控制過程。??
???
???
??VxD?API??
???
???
??在前面的文章中,我們說MYFIRST.VxD將支持Real/V86?Mode?API及Protected??
???
??Mode?API,這使得MYFIRST.VxD可以與V86應用程序或Win16應用程序通信。??
???
??MYFIRST.VxD輸出的V86?API和PM?API就是??
???
???
??VOID?_cdecl?V86_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs);??
???
???
??VOID?_cdecl?PM_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs);??
???
???
??一個問題很快就擺在我們面前:如何在我們的應用程序中調用到這兩個API???
???
???
??讀一下這段代碼:??
???
???
??DWORD?NEAR?PASCAL?GetAPIEntry(WORD?VxD_ID)??
???
??{DWORD?Entry_Point;??
???
???
??_asm{??
???
???mov?AX,?1684h??
???
???mov?BX,?WORD?PTR?SS:?[VxD_ID]??
???
???sub?DI,?DI??
???
???mov?ES,?DI??
???
???int?2Fh??
???
???mov?WORD?PTR?SS:?[Entry_Point][0],?DI??
???
???mov?WORD?PTR?SS:?[Entry_Point][2],?ES??
???
????????????}?return?Entry_Point;}??
???
???
??這段代碼可以用在MS_DOS應用程序或是Win16應用程序中,函數GetAPIEntry將分?
??
???
??別返回V86_Api_Handler的地址或PM_Api_Handler的地址。??
???
???
??等一下,函數GetAPIEntry的入口參數VxD_ID是怎么回事?嗯,問得好。如果你?
一??
???
??直在讀我的文章,那你會發現我們在前面有一個失誤:在用QuickVxD生成??
???
??MYFIRST.VxD的源程序時,把MYFIRST.VxD的DeviceID置成了UNDEFINED_??
???
??DEVICE_ID。通過在VToolsD\include\Vmm.h中查找,可以看到:??
???
???
??#define?UNDEFINED_DEVICE_ID?0x00000??
???
???
??也就是說所有UNDEFINED_DEVICE_ID的VxD的DeviceID都置成了0。如果我們??
???
??向函數GetAPIEntry傳遞MYFIRST_DeviceID,那我們很可能無法獲得??
???
??MYFIRST.VxD中的API的地址,因為我們的DeviceID不是惟一的,Windows無法在?
??
???
??眾多DeviceID為0的VxD中找到我們的MYFIRST.VxD。那怎么辦呢???
???
???
??解決方案有兩個:??
???
???
??方案一:??
???
??再用QuickVxD重新生成MYFIRST.VxD的源程序。記著在Device?Parameters頁中填?
??
???
??寫Device?ID為某個值,這個值盡量大一些,因為比較小的DeviceID都讓?
Microsoft或??
???
???
??是別的硬件開發商注冊了(注冊是需要銀子的),為了保證不與系統中現存的?
VxD??
???
??的DeviceID發生沖突,我們只好把DeviceID設得大一些,比如說0xAAAA。??
???
???
??方案二:??
???
??編輯一下MYFIRST.H,把MYFIRST_DeviceID改了,改過之后的MYFIRST.h如下??
???
??:??
???
???
??#include?〈vtoolsc.h〉??
???
??#define?MYFIRST_Major?1??
???
??#define?MYFIRST_Minor?0??
???
??#define?MYFIRST_DeviceID?0xAAAA??
???
??#define?MYFIRST_Init_Order?UNDEFINED_INIT_ORDER??
???
???
??好了,我們已經準備好與我們的MYFIRST.VxD通信了。??
評論
查看更多