小默

coinstaller--DDK文档翻译zz

编写协同安装程序
协同安装程序是微软公司开发的win32的DLL,它是用来帮助在Windows 2000系统上进行设备安装。它被Setup API调用作为类安装程序的“助手”。例如,供应商可以提供协同安装程序将特定设备信息写入INF文件无法处理的注册表中。

本章内容:
l 4.1 协同安装程序总览
l 4.2 协同安装程序界面
l 4.3 协同安装程序操作
l 4.4 注册协同安装程序
1.1 协同安装程序总览
由Setup API调用的协同安装程序如图4-1所示。
图4-1 协同安装程序在设备安装中的分工
带有阴影的方框表示可由IHV和OEM提供的组件,其他组件则由OS提供。参见第1章“设备安装总览”可以了解更多的有关安装组件的信息。
协同安装程序可以是设备专用或类专用的。Setup API只在安装协同安装程序为其注册的设备时才调用一个设备专用的协同安装程序。操作系统(OS)及供应商可以为一个设备注册零个或多个设备专用的协同安装程序。在为协同安装程序注册安装设备设置类的任何设备时,Setup API调用类协同安装程序。操作系统及供应商可以为一个设备设置类注册一个或多个类协同安装程序。除此之外,类协同安装程序还可以为一个或多个设置类注册。

GUI模式设置、新设备DLL以及定制设置应用程序通过调用带有设备安装函数代码(DIF代码)的SetupDiCallClassInstaller来安装设备。对于每一个DIF请求,SetupDiCallClassInstaller调用为设备设置类注册的任何类协同安装程序,调用为特定设备注册的任何设备协同安装程序,以及由系统提供用于设备设置类的类安装程序(如果有的话)。

定制设置应用程序须调用SetupDiCallClassInstaller而不是直接调用协同安装程序或类安装程序。这个函数可以保证所有注册的协同安装程序都能被正确调用。

类协同安装程序一般都在设备安装之前注册,而设备专用的协同安装程序则是作为设备安装的一部分被注册的。因此类协同安装程序总是在第一次构建时就被添加到协同安装程序列表之中,并在设备安装时被所有DIF请求调用。特定设备协同安装程序则是在为该设备完成DIF_REGISTER_COINSTALLERS请求之后被添加到重安装列表之中的(或是在调用了SetupDiRegisterCoDeviceInstallers之后)。特定设备协同安装程序并不参与以下DIF请求:DIF_ALLOWINSTALL、DIF_INSTALLDEVICEFILES及DIF_SELECTBESTCOMPATDRV。

如果协同安装程序需要响应以下任何一个DIF请求,它就必须是一个类协同安装程序(而不是设备专用协同安装程序):
l DIF_FIRSTTIMESETUP,DIF_DETECT*
l DIF_NEWDEVICEWIZARD_PRESELECT
l DIF_NEWDEVICEWIZARD_SELECT
l DIF_NEWDEVICEWIZARD_PREANALYZE
l DIF_NEWDEVICEWIZARD_POSTANALYZE

设备协同安装程序并不适用于这样的上下文,这是因为并没有标识出某个特定的设备,或是因为在安装的这个初始阶段还没有注册过设备安装程序。
图4-2显示了在注册了任意一个特定设备的协同安装程序之后,SetupDiCallClassInstaller调用协同安装程序及类安装程序的顺序。

图4-2 为DIF请求调用协同安装程序的处理及后处理示例
在图4-2所演示的示例中,为该设备的设置类注册了两个类协同安装程序以及一个特定设备协同安装程序。以下步骤对应于图4-2中的带圆圈的数字标号:

1. SetupDiCallClassInstaller调用第一个类协同安装程序,同时指定一个表示安装请求正在处理中的DIF代码(在本例中是DIF_INSTALLDEVICE)。协同安装程序在安装请求中有参与的选择权。本例中,第一个注册的类协同安装程序返回NO_ERROR。
2. 接下来,SetupDiCallClassInstaller调用任意额外注册的类协同安装程序。在本例中,第二个类安装程序返回了ERROR_DI_POSTPROCESSING_REQUIRED,它要求在后处理之后再调用协同安装程序。
3. SetupDiCallClassInstaller调用任意注册的设备专用协同安装程序。
4. 在调用了所有的注册过的协同安装程序后,如果设备的设置类有一个系统提供的类安装程序,SetupDiCallClassInstaller就调用它。在本例中,类安装程序返回ERROR_DI_DO_DEFAULT,这是类安装程序的一个典型返回值。
5. 如果有一个缺省的设备处理驱动程序,SetupDiCallClassInstaller就为安装请求调用它。DIF_INSTALLDEVICE有一个缺省的设备处理驱动程序SetupDiInstallDevice,它是Setup API的一部分。
6. SetupDiCallClassInstaller调用任何要求后处理的协同安装程序。在本例中,第二个类协同安装程序要求了后处理。
除了协同安装程序在它的单个入口点被再一次调用外,协同安装程序的后处理与驱动程序的IoCompletion例程相似。当SetupDiCallClassInstaller为后处理调用协同安装程序时,它将PostProcessing设为TRUE,并将InstallResult设为Context参数中的恰当值。在本例中,Context.InstallResult是NO_ERROR,这是因为成功地执行了缺省的设备处理驱动程序。
在后处理中,SetupDicallClassInstaller反向调用了协同安装程序。如果图4-2中的所有协同安装程序都已返回了ERROR_DI_POSTPROCESSING_REQUIRED,那么SetupDiCallClassInstaller就会为后处理先调用Device_Coinstaller_l,之后再是Class_Coinstaller_2,和Class_Coinstaller_1。类安装程序并不要求后处理,只有协同安装程序才要求。
即使先前的协同安装程序在安装请求中失败,要求后处理的协同安装程序也会被调用。
1.2 安装程序界面
协同安装程序具有以下原型:
typedef
DWORD
( CALLBACK* COINSTALLER_PROC) (
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DADA DeviceInfoData OPTIONAL,
IN OUT PCOINSTALLER_CONTEXT_DATA Context
);
InstallFunction指定了正被处理的设备安装请求,在其中协同安装程序具有参与的选择权。例如,DIF_INSTALLDEVICE。参见《Windows 2000 Driver Development Reference》一书的第一卷第3部分的第5章“安装功能代码”有关“在DIF代码上的文档处理”内容。
DeviceInfoSet提供了一个设备信息集的标识值。
DeviceInfoData有选择性地标识作为设备安装请求的目标设备。如果这个参数是非NULL的,它就在设备信息集中标识一个元素。当SetupDiCallClassInstaller调用一个特定设备协同安装程序时,DeviceInfoData为非NULL。特定类协同安装程序可以同一个具有NULL DeviceInfoData的DIF请求(如DIF_DETECT或DIF_FIRSTTIMESETUP)一起被调用。
Context指向该安装请求的特定协同安装程序上下文结构。这个上下文信息的格式如下:
Typedef struct
_COINSTALLER_CONTEXT_DATA {
BOOLEAN PostProcessing;
DWORD InstallResult;
PVOID PrivateData;
} COINSTALLER_CONTEXT_DATA, *PCOINSTALLER_CONTEXT_DATA;

当在恰当的类安装程序(如有的话)处理了InstallFunction之后再调用协同安装程序时,PostProcessing为TRUE。PostProcessing对协同安装程序是只读的。
如果PostProcessing为FALSE,则InstallResult不相关。如果PostProcessing为TRUE,InstallResult就是安装请求的当前状态。该值为NO_ERROR或是一个由为该安装请求调用的先前部分返回的错误状态。协同安装程序可以为它的函数返回通过返回该值传送状态,或者可以返回其他状态。InstallResult对协同安装程序是只读的。
PrivateData指向一个被分配的协同安装程序缓冲。如果协同安装程序设置该指针并要求后处理,那么当SetupDiCallClassInstaller为后处理调用协同安装程序时,将该指针传给这个协同安装程序。
设备协同安装程序返回以下一个值:
l NO_ERROR
协同安装程序对特定的InstallFunction执行恰当的动作,或协同安装程序决定它无需为该请求执行任何操作。
l ERROR_DI_POSTPROCESSING_REQUIRED
协同安装程序对特定的InstallFunction执行任何恰当的操作,同时在类安装已处理了该请求之后并要求被再次调用。
l A Win32 error
协同安装程序遇到一个错误。
协同安装程序不会设置ERROR_DI_DO_DEFAULT的返回状态。这个状态只能由类安装程序使用。如果一个协同安装程序返回了这样的状态,那么SetupDiCallClassInstaller将不能正确地处理DIF_Xxx请求。协同安装程序也可能在后处理传送中传输ERROR_DE_DO_DEFAULT的一个返回状态,但是它永远不会设置这个值。
1.3 协同安装程序操作
协同安装程序是用户模式的Win32 DLL,它为注册编写额外的配置信息或执行要求动态信息的其他安装任务,而该动态信息无法通过编写INF来得到。
协同安装程序可以完成以下一些或所有的任务:
l 打开InstallFunction来处理仅一个或少量的DIF_Xxx请求。
l 根据它是否被后处理调用来执行不同的操作(也就是Contex->PostProcessing是否为TRUE?)
l 当为后处理调用时,检查Context->InstallResult。如果它不是NO_ERROR,就进行任何必需的清除并返回InstallResult。
协同安装程序必须不能给最终用户显示任何的UI。协同安装程序应该为设备提供恰当的缺省值。如果它没有缺省值并要求用户输入,那么其他的设备支持组件就应提示用户稍后的所需输入。例如,若调制解调器没有正确的拨号属性设置,则需在用户使用调制解调器而不是在设备设置时提示他们。
1.3.1 处理DIF代码
每个DIF代码的参考页都继续了以下一些或全部的部分:
何时发送
描述Setup应用程序发送该DIF请求的典型时间及原因。
由谁处理
指出允许哪些安装程序处理该请求。该安装程序包括了类安装程序、类协同安装程序(设置-类范围的协同安装程序),以及设备协同安装程序(特定设备协同安装程序)。
输入
SetupDiCallClassInstaller通过在它的主入口点调用安装程序给一个安装程序发送一个DIF请求。除了DIF代码之外,这个功能提供与某请求相关的额外信息。参见每个DIF代码的参考页可得到与每个请求一起提供的信息细节。以下列表包括了额外输入的一般描述,还列出了用于处理参数的SetupDiXxx函数:
l DeviceInfoSet
为设备信息集提供一个标识值。
该标识值是不透明的。利用这个标识值,例如,在调用中将设备信息集标识到SetupDiXxx函数。
DeviceInfoSet可能具有相联的设备设置类。如果是这样的,则调用SetupDiGetDeviceInfoListClass以得到类GUID。
l DeviceInfoData
有选择性地给一个SP_DEVINFO_DATA结构提供一个指针,该结构在设备信息集中标识了一个设备。
l Device Installation Parameters
这些非直接的参数为SP_DEVINSTALL_PARAMS结构中的设备安装提供了信息。如果DeviceInfoData是非NULL,就有与DeviceInfoData相关的设备安装参数。如果DeviceInfoData为NULL,则设备安装参数就与DeviceInfoSet相关的设备安装参数。
调用SetupDiGetDeviceInstallParams以得到设备安装参数。
l Class Installation Parameters
将可选的非直接参数指定给某个DIF请求。它们尤其是“DIF请求参数”。例如,一个DIF_REMOVE安装请求的类安装参数被包含在一个SP_REMOVEDEVICE_PARAMS结构中。
每个SP_XXX_PARAMS结构开始于一个固定大小的SP_CLASSINSTALL-HEADER。
调用SetupDiGetClassInstallParams以得到类安装参数。
如果DIF请求具有类安装参数,就有与DeviceInfoSet相关的参数集,及与DeviceInfoData相关的另一个参数集(如果DIF请求指定了DeviceInfoData)。SetupDiGetClassInstallParams返回了可得到的最特定参数。
l 上下文 (Context)
协同安装程序具有一个可选的上下文参数。
l 输出 (Output)
描述这个DIF代码所需的输出。
如果安装程序修改了设备安装参数,那么在返回之前安装程序必须调用SetupDiSetDeviceInstallParams来应用改变。类似地,如果安装程序修改DIF代码的类安装参数,安装程序必须调用SetupDiSetClassInstallParams。
l 返回值 (Return Value)
指定DIF代码的恰当返回值。参见图4-3中有关返回值的更多信息。
l 缺省处理程序 (Default Handler)
指定SetupDi函数,它执行DIF代码的系统定义操作。并非所有的DIF代码都具有缺省处理程序。除非协同安装程序或类安装程序采取步骤阻碍调用缺省处理程序,SetupDiCallClassInstaller才会在它调用类安装程序之后再调用DIF代码的缺省处理程序(但却是在它调用任何为后处理注册的协同安装程序之前)。
操作 (Operation)
描述安装程序可能用来处理DIF请求的典型任务。
其他 (See Also)
相关信息源的列表。
图4-3中是SetupDiCallClassInstaller中处理DIF代码的事件序列。
操作系统执行每个DIF代码的一些操作。由供应商提供的协同安装程序及类安装程序可以参与安装行为。请注意即使DIF代码失败了,SetupDiCallClassInstaller也调用了为后处理注册的协同安装程序。
1.4 注册协同安装程序
协同安装程序可以为某个设置类的单个或全部设备注册。当特定设备中的一个已被安装时,这些设备的协同安装程序就通过INF文件动态注册。类协同安装程序被手工注册或由定制的设置应用程序及一个INF注册。
如要了解更多的信息,可参见《Registering a Device-Specific Coinstaller》及《Registering a Class Coinstaller》。
如要更新协同安装程序,DLL的每个新版本都需有一个新的文件名,这是因为当用户在设备属性页上点击Update Driver按纽时,尤其要用到DLL。
图4-3 在SetupDiCallClassInstaller中的DIF代码处理流程图
1.4.1 注册设备专用的协同安装程序
为了注册设备专用的协同安装程序,将以下部分添加到设备的INF文件中:
; :
; :
[DestinationDirs]
XxxCopyFilesSection = 11 \\DIRID_SYSTEM
\\ Xxx = driver or dev . prefix
; :
; :
[XxxInstall . OS-platporm.CoInstallers] \\ OS-platform is optional
CopyFiles = XxxCopyFilesSection
AddReg = Xxx.OS-platform. CoInstallers_AddReg
[XxxCopyFilesSection]
XxxCoInstall.dll
{Xxx. OS-platform.CoInstallers_AddReg}
HKR,,CoInstallers32.0x00010000.”XxxCoInstall.dll. \
XxxCoInstallEntryPoint”
DestinationDirs部分中的项说明XxxCopyFiles部分中列出的文件将被复制到系统目录下。Xxx前缀标识出驱动程序、设备或设备组(如cdrom_CopyFilesSection)。Xxx前缀应是唯一的。
协同安装程序安装节的名称可以用可选的操作系统/架构扩展(如cdrom_install.NTx86.CoInstallers)来修饰。
Xxx_AddReg部分中的项在设备驱动程序密钥中建立一个CoInstallers32值项。该项包含了协同安装程序DLL,而且可选地还可有一个特定入口点。如果忽略这个输入点,则缺省为CoDeviceInstall。十六进制标志参数(0x00010000)指明这是REG_MULTI_SZ值项。
为了给设备注册多于一个的特定设备协同安装程序,复制每个协同安装程序的文件并在注册项中包含至少一个信息串。例如,为了注册两个协同安装程序,建立如下部分:
; :
; :
[DestinationDirs]
XxxCopyFilesSection = 11 \\DIRID_SYSTEM
\\ Xxx = driver or dev . prefix
; :
; :
[XxxInstall . OS-platporm.CoInstallers] \\ OS-platform is optional
CopyFiles = XxxCopyFilesSection
AddReg = Xxx.OS-platform. CoInstallers_AddReg
[XxxCopyFilesSection]
XxxCoInstall.dll \\ copy 1st coinst. file
YyyCoinstall.dll \\ copy 2nd coinst. file
[Xxx. OS-platform.CoInstallers_AddReg]
HKR..CoInstallers32.0x00010000. \
“XxxCoInstall.dll. XxxCoInstallEntryPoint”. \
“YyyCoInstall.dll. YyyCoInstallEntryPoint”
\\ add both to registry
当执行设备专用的协同安装程序INF部分时,该协同安装程序是在安装一个设备的过程中被注册的。接着Setup API在安装过程中的每个随后步骤上调用协同安装程序。如果为一个设备注册多个协同安装程序,那么Setup API按其在注册中所列顺序调用它们。
1.4.2 注册类协同安装程序
如要为某个设置类的每个设备都注册一个协同安装程序,可按以下所列建立一个注册表项
HKLM\System\CurrentControlSet\Control\CoDeviceInstallers subkey:
{setup-class-GUID}: REG_MULTI_SZ : “XyzCoInstall.dll. XyzCoInstallEntryPoint\0\0”
该系统建立了CoDeviceInstallers密钥。Setup-class-GUID为设备设置类指定GUID。如果协同安装程序提供设备的多个类,它就建立每个设置类的单个值项。
我们不能覆盖先前写给setup-class-GUID密钥的其他协同安装程序。读取这个密钥,将自己的协同安装程序信息串附加到REG_MULTI_SZ列表中,并将该密钥写回到注册表中。
如果忽略CoInstallEntryPoint,则缺省为CoDeviceInstall。
协同安装程序DLL必须也被复制到系统目录下。
一旦复制了文件且做出了注册表项,类协同安装程序就可被用来调用相关设备和服务。
不用手工建立注册项来注册一个类协同安装程序,就可以利用INF文件注册它,如下所示。
[version]
signature = “$Windows NT$”
[DestinationDirs]
DefaultDestDir = 11 / / DIRID_SYSTEM
[DefaultInstall]
CopyFiles = @classXcoinst.dll
AddReg = CoInstaller_AddReg
[CoInstaller_AddReg]
HKLM.System\CurrentControlSet\Control\CoDeviceInstallers, \
{setup-class-GUID}, 0x00010008, “classXcoinst.dll,classXCoInstaller’
; above line uses the line continuation character (\)
这个例子INF将文件classXcoinst.dll复制到系统目录下并在CoDeviceInstallers密钥下建立了一个setup-class-GUID类的项。Xxx-AddReg部分的项指示两个标志:”00010000”标志表示这个项是REG_MULTI_SZ,而”00000008”标志表示新值将被附加到任何已有的值上(如果新值并未存在于信息串中)。
这样一个注册表类协同安装程序的INF可由右点击安装或通过SetupInstallFromInfSection应用程序激活。

贴段伪代码
HRESULT
CoInstaller(
        IN   DI_FUNCTION           InstallFunction,
        IN   HDEVINFO             DeviceInfoSet,
        IN   PSP_DEVINFO_DATA       DeviceInfoData, OPTIONAL
        IN OUT PCOINSTALLER_CONTEXT_DATA Context
        )
{
   
switch(InstallFunction)
   {
   
case DIF_SELECTBESTCOMPATDRV:
       
if(!Context->PostProcessing)
       {
           DbgOut(
"DIF_SELECTBESTCOMPATDRV");

           
return ERROR_DI_POSTPROCESSING_REQUIRED;
       }
       
else //post processing
       {
           DbgOut(
"DIF_SELECTBESTCOMPATDRV PostProcessing");
           
//We will do something here
           SP_DRVINFO_DATA DriverInfoData;

           SP_DRVINSTALL_PARAMS DriverInstallParams;

           DriverInfoData.cbSize 
= sizeof(SP_DRVINFO_DATA);
           DriverInstallParams.cbSize 
= sizeof(SP_DRVINSTALL_PARAMS);

           
if(SetupDiEnumDriverInfo(DeviceInfoSet,DeviceInfoData,SPDIT_CLASSDRIVER ,0,&DriverInfoData))
               
if(SetupDiGetDriverInstallParams(DeviceInfoSet,DeviceInfoData,&DriverInfoData,&DriverInstallParams))
                   
if(DriverInstallParams.Rank != 0)
                       DriverInstallParams.Rank 
= 0;
           
if(!SetupDiGetDriverInstallParams(DeviceInfoSet,DeviceInfoData,&DriverInfoData,&DriverInstallParams))
           {
               DbgOut(
"SetupDiGetDriverInstallParams");
           }

       }
       
break;
   
case DIF_REMOVE:
       DbgOut(
"DIF_REMOVE");
       
break;
   
default:
       
break;
   }
   
return NO_ERROR;
}

posted on 2010-02-06 00:05 小默 阅读(1554) 评论(0)  编辑 收藏 引用 所属分类: Windows


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

留言簿(13)

随笔分类(287)

随笔档案(289)

漏洞

搜索

积分与排名

最新评论

阅读排行榜