把C:\MSDEV\INCLUDE这个路径(其中,C:\MSDEV是VC++的头文件.h文件的路径)修改为您机器安装的VC++的路径即可。
例如,如VC++安装在C:\Program Files\Microsoft Visual Studio\VC98中,就可以将之改为:
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
把D:\WIN95DDK\INC32修改为DDK的安装路径的头文件的路径。
例如,如果DDK的目录为C:\WIN98DDK,就可以将之修改为E:\98DDK\inc\win98。
接下来,就可以编译。可按如下步骤进行:
(1)进入MS DOS方式。
进入STHVxD文件的路径,例如:
CD D:\COOLCPU\STHVxD
(2)运行nmake.exe程序,对整个程序进行编译。当BIN目录下生成SthVxD.VxD的文件时,该VxD就编译完成了。在编译完成后,会出现一些警告,这是正常的,没有什么问题。
② 编译主程序(CoolCpu)
VxD文件编译好后,主程序就很容易编译。只需打开VC++的open workspace文件 CoolCpu.dsp或CoolCPU.mak。
③ 运行程序
直接编译,就可以看到在BIN目录中生成了一个CoolCPU.EXE文件。当在编译环境中,BulidExecute系统将弹出一个写有"can't execute program"的信息提示框。这是为什么呢?
其实,这是CoolCPU.exe在当前的编译目录中找SthVxD.VxD的文件,因为当前路径下没有这个VxD文件,所以就弹出错误的对话框。直接到BIN文件下运行CoolCPU.exe,就可以看见在Windows的任务栏的右下角出现了一个小云雨的图标。当单击此图标时,弹出菜单,"空闲时让CPU节能"的小钩被打上时,表示允许CPU使用降温功能。去掉小钩时,表示不用此降温功能。
- 程序的分析
下面我们来分析一下这个程序。
首先看一下VxD的基本框架。从CVxDctrl.asm文件中,可以看到如下的程序结构。
PAGE 58,132
;*********************************************************
TITLE CONTROL - ControlDispatch for VxD in C
;********************************************************
;
.586p
;*********************************************************
; 包含头
;*********************************************************
.xlist
include vmm.inc
include debug.inc
.list
;编译成动态VxD,动态的VxD为1
SthVxD_DYNAMIC EQU 1
;VxD的ID号
CVxD_DEVICE_ID EQU 0ABCH
ifdef _VxD_SERVICES
;定义可以被其他VxD调用的接口函数
Create_CVxD_Service_Table = 1
;可以被其他VxD调用的接口函数表
Begin_Service_Table CVxD
CVxD_Service _CVxD_Get_Version, VxD_LOCKED_CODE
End_Service_Table CVxD
Endif
很多人可能对汇编不是很熟悉,但这不要紧。在这段汇编中用了很多的宏汇编语句,使整个代码很像高级语言。
在VxD的这段汇编的代码中,很多东西是必须的,下面我们来分别介绍。
.586p
告诉编译器要使用CPU特权指令的80586指令系统,还可以使用.386p或者.486p等。
include vmm.inc
每个VxD源代码都必须包含imm.inc。它包含了代码中宏的定义。可以根据需要包含其他的库文件,如Pci.inc(PCI设备)的宏。
SthVxD_DYNAMIC EQU 1
表示SthVxD_DYNAMIC等于1,相当于C语言中的#define语句的作用。
CVxD_DEVICE_ID EQU 0ABCH
每个VxD程序的16位惟一标识符,有了这个ID就可以导出一些供其他VxD程序使用的VxD服务。
如果VxD程序不需要一个惟一的设备ID,可以把这一项设为UNDEFINED_DEVICE_ID ,还可以由微软分配一个固定的ID号。也可以任意设置,只要以前没有使用过,此处设置为0ABCH。
ifdef _VxD_SERVICES
;定义可以被其他VxD调用的接口函数
Create_CVxD_Service_Table = 1
;可以被其他VxD调用的接口函数表
Begin_Service_Table CVxD
CVxD_Service _CVxD_Get_Version, VxD_LOCKED_CODE
End_Service_Table CVxD
Endif
定义被其他函数调用的接口的申明,很多VxD中的函数可以给其他的VxD进行调用,有些VxD提供了一此功能能让别的VxD使用,就可以像动态连接库一样引出一些函数。
DECLARE_VIRTUAL_DEVICE SthVxD, 5, 0, CVxD_Control, CVxD_DEVICE_ID,\ UNDEFINED_INIT_ORDER, CVxD_V86, CVxD_PM
VxD_LOCKED_CODE_SEG
这是一个标准的VxD的说明部分,VMM通过VxD程序的设备描述块(DDB)来获取VxD的有关的信息。一个设备描述块是一个结构,它包含了许多关于VxD的重要信息,查阅DDB表可以知道。
SthVxD为VxD的名称,5为主版本号,0为副版本号,CVxD_Control为指向VxD的消息处理函数的指针,CVxD_DEVICE_ID为设备ID号。UNDEFINED_INIT_ORDER是初始化的序列,可以通过这个序列号让VMM来决定是装入时初始化还是随机地初始化或者是一定要在某事件前初始化,但一般的VxD是不必要设置这个参数的,它一般用在系统的某些固定的设备的VxD上。CVxD_V86为V86的处理函数,CVxD_PM为保护模式程序使用的API地址。
在上面这段代码中,我们还可以看到VxD_LOCKED_CODE_SEG这个语句,它是什么呢?
其实,它是vmm.inc中的宏语句,表示代码在内存中的一种存储方式,请参考介绍LE的文件模式的一节。