汇编教程:虚拟设备驱动程序结构
2008-12-27 09:35:51 来源:WEB开发网VxD结构
现在你了解了LE文件里的段,我们可以继续来看一下源文件。你会发现VxD程序有一个特点,那就是它用了很多的宏。你可以看到在VxD中宏几乎无处不在,这都成为一个习惯了。这些宏用来隐藏一些底层的细节,也增加了源程序的可移植性。如果你有兴趣,你可以看一看像vmm.inc这一类的库文件中的这些宏的定义。
下面是VxD源文件结构:
.386p
include vmm.inc
DECLARE_VIRTUAL_DEVICE FIRSTVXD,1,0, FIRSTVXD_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_control_dispatch FIRSTVXD
End_control_dispatch FIRSTVXD
end
这段源程序给人的第一印象就是:它并不像一个汇编源程序。那是因为它用了很多宏。让我们来分析一下源程序以便你能很快理解它。
.386p
告诉编译器我们要使用包括CPU特权指令的80386指令系统。你也可以使用.486p或者.586p.
include vmm.inc
你的每个VxD源程序都必须包含imm.inc,因为它包含了你在源程序里所要用到的宏的定义。你还可以根据需要包含其他的库文件。
DECLARE_VIRTUAL_DEVICE FIRSTVXD,1,0, FIRSTVXD_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
正如我们刚才说的,VMM通过VxD程序的设备描述块(DDB)来获取它所需要知道的关于VxD的所有信息。一个设备描述块是一个结构,它包含了许多关于VxD的重要信息,比如VxD的名字,它的设备ID,它的VxD服务函数入口(如果有的话),等等。你可以在imm.inc里查一查这个结构,它被定义为VxD_Desc_Block。你必须在.DEF 文件里导出这个结构。这个结构有22个数据,但是你只用填写其中的几个。然后vmm.inc包含的一个宏会为你初始化并填写这些数据。这个宏叫做DECLARE_VIRTUAL_DEVICE。它的格式如下:
Declare_Virtual_Device Name, MajorVer, MinorVer, CtrlProc, DeviceID, InitOrder, V86Proc, PMProc, RefData
你可以看到:VxD源程序中的标号是不区分大小写的,你可以用大写,小写或者混合起来用都可以。让我们来看一下Declare_virtual_device里的每一个参数。
Name VxD的名字 最多8个字符。它必须是大写!在系统中的所有VxD程序里,它们的名字不能重复,每个VxD的名字应该是唯一的。这个宏同时也会根据这个名字产生DDB的名字,产生的办法就是:在这个名字的后面加上_DDB。所以如果你的VxD的名字是FIRSTVXD, Declare_Virtual_Device这个宏就会把DDB的名字定为FIRSTVXD_DDB。记住,你还要在.DEF文件里导出DDB。所以你必须使DDB的名字和.DEF文件定义中的相同。
MajorVer 和 MinorVer 你的VxD的主要的和次要的版本。
CtrlProc 你的VxD程序的设备控制函数的名字。设备控制函数是一个接受和处理VxD程序的控制消息的函数。你可以把设备控制函数看作Window函数的等价物。既然我们要用Begin_Control_Dispatch这个宏来生成我们的设备控制函数,那么我们应该使用一个标准格式的名字,那就是VxD的名字_Control。 Begin_Control_Dispatch这个宏把_Control 加到它后面的那个名字上(而我们又通常把VxD的名字写在它后面)作为设备控制函数的名字,所以我们就应该把VxD的名字加上_Control作为CtrlProc 参数的值。
DeviceID 你的VxD程序的16位唯一标识符 当且仅当你的VxD程序需要处理以下情况时你需要用到这个ID:
你的VxD程序导出一些供其他VxD程序使用的VxD服务。因为20H中断接口用设备ID来定位/区分VxD程序,所以一个唯一的ID对你的VxD程序是必要的。
Your VxD 你的VxD程序要在初始化中断2FH,1607H时通知实模式程序它的存在。
Some 一些实模式软件(TSR)要用中断2FH,1605H来加载你的VxD程序。
如果你的VxD程序不需要一个唯一的设备ID,你可以把这一项设为UNDEFINED_DEVICE_ID ,如果你需要它,你可以去Microsoft要一个。
InitOrder 初始化的顺序,简单的说,就是加载的顺序。VMM就按照这个次序来加载VxD程序。每个VxD程序都有一个加载次序号,例如:
VMM_INIT_ORDER EQU 000000000H
DEBUG_INIT_ORDER EQU 000000000H
DEBUGCMD_INIT_ORDER EQU 000000000H
PERF_INIT_ORDER EQU 000900000H
APM_INIT_ORDER EQU 001000000H
你可以看到:VMM, DEBUG和 DEBUGCMD是首先加载的VxD程序,然后是PERF和APM。初始化顺序值越低的VxD程序越先被加载。如果你的VxD程序在初始化时需要用到其他VxD程序提供的服务,那么你必须把初始化顺序的值设得比你所要调用的那个VxD程序的大,这样,当你的VxD程序加载时,你所要的VxD就已经在内存中为你准备好了。如果不想去管你的VxD的初始化顺序,就把这个参数填写为UNDEFINED_INIT_ORDER 。
V86Proc和PMProc 你的程序可以导出供V86和保护模式程序使用的API,这两个参数就是用来填写这些API的地址。记住,VxD程序除了监控系统虚拟机外,还要监控一个或多个运行在DOS或者保护模式下的虚拟机程序。理所当然的,VxD程序要为DOS和保护模式程序提供API支持。如果你不导出这些API,你可以不填这两个参数。
RefData 输入输出监视器(IOS)要用到的参考数据。只有一种情况下你要用到这个参数:当你在为IOS编写一个层驱动程序时。否则,你可以不填这个参数。
接下来是 Begin_Control_Dispatch宏。
Begin_control_dispatch FIRSTVXD
End_control_dispatch FIRSTVXD
这两个宏定义了设备控制函数,当VxD的控制消息发生时,VMM就调用这个函数。你必须填写设备控制函数名字的前半部分,在本例中,我们用的是 FIRSTVXD。这个宏会在你输入的前半部分后加上_Control作为设备控制函数的名字。这个名字一定要和你在Declare_virtual_device 宏中给参数CtrlProc填的名字一致。设备控制函数总是放在锁定段(VxD_LOCKED_CODE_SEG)内的。上面定义的设备控制函数什么也不干。你需要说明你的VxD程序要响应什么控制消息,以及处理这个消息的函数,你可以用Control_Dispatch宏来实现这一点。
Control_Dispatch message, function
例如,如果你的VxD程序只要处理Device_Init 消息,你的设备控制程序要这样写:
Begin_Control_Dispatch FIRSTVXD
Control_Dispatch Device_Init, OnDeviceInit
End_Control_DispatchFIRSTVXD
OnDeviceInit就是要处理Device_Init消息的函数的名字。你可以给你的函数取任何你想取的名字。
你可以用end 直接地结束你的VxD源程序。
综上所述,一个VxD程序至少包含一个设备控制块和一个设备控制函数。你要用Declare_Virtual_Device宏来定义一个设备控制块,用Begin_Control_Dispatch宏来定义一个设备控制程序。你必须在.def文件中的EXPORTS下面填写设备控制块的名字,从而导出该设备控制块。
更多精彩
赞助商链接