所谓“协作安装程序”,在ddk文档里面称作co-installer,有人将它翻译成“共同安装程序”。但是,
从ddk文档对co-installer功能的描述来看,我个人觉得翻译成“协作安装程序”更恰当些。
ddk文档对co-installer的描述:A co-installer is a Microsoft® Win32® DLL that assists in
device installation. Co-installers are called by Setup API as "helpers" for Class
Installers.简单地翻译一下:协作安装程序是一个Win32 DLL,它辅助设备的安装。协作安装程序
由Setup API调用,作为类安装程序的“助手”。
在本论坛搜索了一下有关“协作安装程序”的帖子,发现这方面的帖子很少。我想之所以这样,是因为
大家在驱动开发过程中可能很少有需要用到协作安装程序的地方。或者说本来有些地方可以使用,但可能
因为不太了解这方面的东西,所以没有想到去用它。
这儿,我想介绍一个关于协作安装程序的应用实例。
开发过USB设备驱动的朋友,不知有没有碰到过下面的问题:如果你的设备驱动程序没有经过数字签名,
那么,在XP系统下,你在每个USB口上第一次插上你的USB设备时,系统都会要求你装一次驱动程序。
这种感觉是很不好的。我们希望能像大多数USB移动盘一样,插上设备就自动安装驱动,然后就可以对
设备进行访问了。
如何让我们的USB设备插上后,系统也能自动为它安装驱动,而不需要烦劳用户手动安装呢?解决此问题
的核心技术在于编写一个类协作安装程序。
首先,有一个问题大家要清楚,USB设备第一次插到机器上的一个USB口上时,系统要为它
装一次驱动程序。我们以USB设备为例,来了解一下支持热插拔的PnP设备的安装过程:
(1)设备插入系统,USB总线驱动向内核PnP管理器报告有新设备接入系统;
(2)内核PnP管理器向USB总线驱动询问设备的具体信息,比如PID和VID等;
(3)内核PnP管理器将设备的信息报告给用户层的PnP管理器,并要求它为新设备安装驱动;
(4)用户层PnP管理器调用系统的Setup组件来为设备安装驱动;
(5)Setup使用设备VID和PID到%Windir%\\inf下寻找适合它的inf文件,并获得一个可用于设备的驱动程序列表;
(6)Setup在生成驱动程序列表的时候,会检查inf文件是否经过数字签名,如果没有经过数字签名,
Setup会将此inf文件负责安装的驱动程序设置成“不可信任的”驱动程序;
(7)Setup对驱动程序列表中的各驱动程序信息进行分析,选择最匹配设备的驱动程序进行安装;
这里,有必要提一下“不可信任的驱动程序”这个概念。这个概念在xp之后才有的,2k和98没有。在Setup
生成的驱动程序列表中,每个驱动程序的信息结构中都有一个Rank字段。在xp中,0x0 < Rank <= 0x3FFF的
驱动程序被认为是“可信任的”;0x8000 <= Rank <= 0xFFFF的驱动被认为是“不可信任的”。如果我们的
驱动程序没有经过数字签名,那么它的Rank值肯定落在0x8000到0xFFFF之间。
再回到前面的安装过程,如果驱动程序中有适合设备的“可信任”驱动程序,那么系统自动对它进行安装;
如果驱动程序列表中的所有驱动程序都是“不可信任的”,那么系统就会弹出“发现新硬件”向导,要你提
供更好的驱动程序,或者要你确认安装“不可信任的”驱动程序。这就是为什么在xp系统下,即便你在一个
USB口上已经安装了设备的驱动程序,你再换个口插上设备,系统又会提示你安装驱动程序的原因。
说了半天,我想现在各位肯定都明白过来了:影响设备驱动程序自动安装的主要原因,是因为我们的
驱动程序被系统认为是“不可信任的”。而系统判断一个驱动程序是否“可信任”,是通过驱动程序信息结
构中的Rank字段的值来判断的。那么,如果我们能把我们的驱动程序信息中的Rank值修改到“可信任”空间,
那么系统是否就会信任我们的驱动程序,而自动对它进行安装呢?答案是,有可能。我不敢说肯定可以,原因
后面会提到。但是,如何修改驱动程序信息的Rank值呢?这就要用到“协作安装程序”。
我们知道,在设备的安装过程中,Setup要向设备类安装程序、类协作安装程序和设备协作安装程序发送
“设备安装功能码”(如果有这些安装程序的话)。ddk文档中又说,类安装程序和类协作安装程序可以对
DIF_SELECTBESTCOMPATDRV请求进行处理(设备协作安装程序不可以)。在对DIF_SELECTBESTCOMPATDRV进行处理
的时候,类安装程序和类协作安装程序可以修改驱动程序列表中各驱动程序的信息。答案越来越清晰了,我们
只要写一个类协作安装程序,对DIF_SELECTBESTCOMPATDRV进行处理,修改我们想要安装的驱动程序的Rank值,
那么就可能骗过系统,使系统相信我们的驱动程序,并完成自动安装。关于编写协作安装程序的具体要求和方法,
可以参考ddk文档中的“Writing a Co-installer(编写协作安装程序)”和ddk\src\general\toaster\coinstaller。
接下来,我们来了解一下,在类协作安装程序处理DIF_SELECTBESTCOMPATDRV时,应该做哪些事情。
(1)首先,调用SetupDiEnumDriverInfo遍历驱动程序列表,获得每个驱动程序的信息――一个
SP_DRVINFO_DATA结构。
(2)接着,用(1)中获得的SP_DRVINFO_DATA作为输入参数,调用SetupDiGetDriverInstallParams,
获得驱动程序安装参数――一个SP_DRVINSTALL_PARAMS结构,其中我们想要修改的Rank赫然在列。你可以按
照自己的需要修改Rank的值,在这儿我们肯定是要把它改为0了(0表示驱动程序与设备最匹配)。
(3)最后,把修改后的SP_DRVINSTALL_PARAMS结构作为输入,调用SetupDiSetDriverInstallParams将我们修改
的值设置生效。
在类协作安装程序中只需作如此处理,便可以使Setup此后信任我们的驱动程序,从而达到我们想瞒天过海的目的。
再稍微提一下类协作安装程序的注册。协作安装程序做好了,如何使它参与到设备安装的过程中来呢?我们
必须注册它。ddk文档对此讲得非常清楚了,参看“Registering a Class Co-installer”,我就不在这儿把它翻译出来了。
最后,要提醒一点:必须为我们的usb设备定义一个新的设备setup类,然后将我们的协作安装程序注册为这个
setup类的类协作安装程序。如果我们让设备仍然属于usb setup类,并将我们的类协作安装程序注册为usb
setup类的一个协作安装程序,那么在安装过程中,Setup仍然弹出一些窗体影响我们设备的自动安装,似乎我们的小聪明
并没能瞒过它。这就是前面我说修改Rank值为“可信任”只是有可能瞒过系统而不是肯定能够瞒过系统的原因。为什么会出现
这种情况呢?从现象看,我感觉是usb setup类的类安装程序仍然发现我们的驱动程序是不可信任的。但是,Setup是以类协作
安装程序、设备协作安装程序和类安装程序的顺序调用它们的,在Setup调用usb setup类安装程序之前,我们已经修改了驱动程序的
Rank值。按理说,它应该不会发现驱动程序是不可信任的。这是一个问题,具体原因我还没有弄明白,希望有知其所以然者,能给
点提示!不管如何,通过实验我发现,只要我们定义了新的setup类,那么我们就可以骗过系统Setup组件,使其自动为我们的设备
安装驱动程序。
就写这些,有兴趣的朋友可以试一下!我不想把具体的实现过程一步一步地写出来,更不愿提供具体的实现代码。
因为我认为只要把原理和方法讲清楚了(但愿我讲得还算清楚),每个人都可以在此基础上做自己的事情。
不管各位朋友看完之后感觉如何,能夸就夸夸,该骂就骂骂,都顶一下!