MS将于今年10月推出win10 RS3 RTM版,并要求OEM厂商的驱动程序必须支持新的D/C/H/U驱动框架(微软爸爸一声令下,苦了我们)。其中的"C"项要求过滤驱动的inf文件必须以扩展INF(Extension inf的概念在Win10上首次提出)的方式安装。经过一番痛苦的摸索,终于把公司大部分的过滤驱动的inf文件转为扩展INF。你以为我会写怎么支持DCHU?呵呵,参考今年WinHEC的资料吧~我写这篇文章是为了总结在支持Extension INF的过程中,观察Setupapi.dev.log日志得到的感悟。在开始之前,先概括的说一下安装设备的流程:首先由"Device installation Application"(设备安装程序)直接间接的调用SetupDiCallClassInstaller发出"DIF_CODE"(DIF码),DIF码依次经过"Class co-installer"/"Device co-installer",最后到达"Class installer",类安装器经过处理后,这个DIF码最终被"default handler"(系统默认的处理器)处理,这些默认处理器就是各种SetupDixxx API,他们处理由SetupDiCallClassInstaller发出的DIF码。整个处理流程简单的说就是SetupDiCallClassInstaller在设备安装的不同阶段会发出各种类型的DIF码,Pnp管理器查找注册表,找到对应的Co-Installer/Class Installer,并最终调用DIF码对应Default Handler进行操作。
可以把这个流程看做一种进程间的通信:设备安装器模块(进程A)为了安装设备,向系统设备安装模块(进程B,应该是Pnp管理器)发出请求,中间可能通过其他系统自带的/用户自定义的模块,各个模块通力合作最终完成安装。
1.Device Installation Application
int cmdInstall(__in LPCTSTR BaseName, __in LPCTSTR Machine, __in DWORD Flags, __in int argc, __in_ecount(argc) TCHAR* argv[])
{
HDEVINFO DeviceInfoSet = INVALID_HANDLE_VALUE;
SP_DEVINFO_DATA DeviceInfoData;
GUID ClassGUID;
TCHAR ClassName[MAX_CLASS_NAME_LEN];
...
if (!SetupDiGetINFClass(InfPath,&ClassGUID,ClassName,sizeof(ClassName)/sizeof(ClassName[0]),0));
DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID,0);
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiCreateDeviceInfo(DeviceInfoSet,
ClassName,
&ClassGUID,
NULL,
0,
DICD_GENERATE_ID,
&DeviceInfoData));
if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
&DeviceInfoData,
SPDRP_HARDWAREID,
(LPBYTE)hwIdList,
(lstrlen(hwIdList)+1+1)*sizeof(TCHAR)));
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE,
DeviceInfoSet,
&DeviceInfoData));
...
在cmdInstall函数的结尾,程序以DIF_REGISTERDEVICE为参数调用SetupDiCallClassInstaller函数。从函数名隐约可以看出,设备安装程序在安装设备时,会调用ClassInstaller----类安装器。在文章的开头部分已经提过设备安装的流程,纵观整个流程,是DIF码把这些零散的组件联系在一起。当然了设备安装程序就是整个流程的源头,是它发出了向ClassInstaller发出了DIF码。
2.Co-Installer
3.Class Installer
4.Default DIF Code Handler
5.应用
>>> [Device Uninstall (Device Manager) - ROOT\SYSTEM\0002]
>>> Section start 2017/08/24 21:49:01.644
cmd: "C:\Windows\system32\mmc.exe" /s C:\Windows\system32\compmgmt.msc
inf: {SetupUninstallOEMInf: oem44.inf}
inf: Driver Store location: C:\Windows\System32\DriverStore\FileRepository\bus.inf_x86_neutral_13a2bbb5fc11723b\bus.inf
sto: {Delete Driver Package: C:\Windows\System32\DriverStore\FileRepository\bus.inf_x86_neutral_13a2bbb5fc11723b\bus.inf} 21:49:01.693
sto: Deleting driver package from Driver Store:
sto: Driver Store = C:\Windows\System32\DriverStore (Online | 6.1.7601)
sto: Driver Package = C:\Windows\System32\DriverStore\FileRepository\bus.inf_x86_neutral_13a2bbb5fc11723b\bus.inf
sto: Flags = 0x00000000
pol: {Driver package policy check} 21:49:01.946
pol: {Driver package policy check - exit(0x00000000)} 21:49:01.948
sto: {Unstage Driver Package: C:\Windows\System32\DriverStore\FileRepository\bus.inf_x86_neutral_13a2bbb5fc11723b\bus.inf} 21:49:01.951
idb: Published INF 'oem44.inf' deleted
idb: Unpublished driver store entry 'bus.inf_x86_neutral_13a2bbb5fc11723b'.
sto: Published driver package INF 'oem44.inf' was deleted.
idb: Unregistered driver store entry 'bus.inf_x86_neutral_13a2bbb5fc11723b'.
sto: {Delete Directory: C:\Windows\System32\DriverStore\FileRepository\bus.inf_x86_neutral_13a2bbb5fc11723b} 21:49:02.161
sto: {Delete Directory: exit(0x00000000)} 21:49:02.170
sto: {Unstage Driver Package: exit(0x00000000)} 21:49:02.179
sto: Deleted driver package from Driver Store. Time = 484 ms
sto: {Delete Driver Package: exit(0x00000000)} 21:49:02.192
inf: Uninstalling catalog: C:\Windows\INF\oem44.CAT
inf: {SetupUninstallOEMInf exit (0x00000000)}
dmg: Successfully uninstalled oem44.inf.
dvi: {DIF_REMOVE} 21:49:02.333
dvi: No class installer for 'Toaster Bus Enumerator'
dvi: Using exported function 'CriticalDeviceCoInstaller' in module 'C:\Windows\system32\SysClass.Dll'.
dvi: CoInstaller 1 == SysClass.Dll,CriticalDeviceCoInstaller
dvi: CoInstaller 1: Enter 21:49:02.344
dvi: CoInstaller 1: Exit
dvi: Default installer: Enter 21:49:02.349
dvi: {Remove DEVICE}
dvi: InstanceID = 'ROOT\SYSTEM\0002'
dvi: Devnode Status = 0x0180200b
dvi: CM_Query_And_Remove_Subtree_Ex returns 0x00000000
dvi: Devnode Status after CM_Query_And_Remove_Subtree_Ex = 0x01802401
dvi: Query-and-Remove succeeded
dvi: {Delete DEVICE}
dvi: Device Instance uninstalled.
dvi: {Delete DEVICE exit (0x00000000)}
dvi: {Remove DEVICE exit (0x00000000)}
dvi: Default installer: Exit
dvi: {DIF_REMOVE - exit(0x00000000)} 21:49:05.749
<<< Section end 2017/08/24 21:49:05.765
<<< [Exit status: SUCCESS]
在>>>>和<<<<之间的是日志体,其中"inf:"指inf文件操作;"sto:"指driver store操作;"dvi:"指设备安装操作。在上面的日志中,我们可以看到字段"{DIF_REMOVE}",这是由设备管理器发出的DIF码;为了处理这个DIF码,Pnp管理器搜索类安装器并打印:"No class installer for 'Toaster Bus Enumerator';搜索协安装器:SysClass.dll;并发送Query_Remove请求删除设备,这段和MSDN上的描述很相似:
DIF_REMOVE:
Default DIF Code Handler:
SetupDiRemoveDevice
Installer Operation:
...
Installers should not delete files when handling this DIF request, in case the files are in use by another device.
Windows sends this DIF request before it initiates PnP query-remove and remove processing.
最后删除设备{Delete DEVICE},而删除设备的操作又和SetupDiRemoveDevice的描述很像:
SetupDiRemoveDevice:
SetupDiRemoveDevice removes the device from the system.
It deletes the device's hardware and software registry keys and any hardware-profile-specific registry keys (configuration-specific registry keys).
如果上面过程中有一步出错,可以先找到DIF码,然后按图索骥找到对应的Default Handler函数,最后定位错误。