上面的参数中,有三个要说明的:
ClassGuid、Enumerator和Flags,都是过滤标志。设置了他们之后,系统所有的设备,只有符合这三个条件的才被放到设备信息集合中。
ClassGuid自然是指设备类或设备接口类的GUID,比如USB的GUID为{36FC9E60-C465-11CF-8056-444553540000}等。
Enumerator笔者翻译为枚举子。啥意思呢?一般来说,设备ID就是设备的枚举子。所以如果像上例中设置为“USB”,则所有设备ID中包含“USB”的都将被包括,故而像“USB/VID_04B4&PID_8613”这样的设备,都被包含其中——其实这个枚举子包含了系统中全部的USB设备。
Flags值有多种选择,DIGCF_ALLCLASSES范围最广:对全部的任何设备类或接口类有支持的设备;DIGCF_DEVICEINTERFACE:仅包含支持设备接口类的设备;DIGCF_DEFAULT:仅包含支持默认接口类的设备;DIGCF_PRESENT:当前连接的设备;DIGCF_PROFILE:Hardware Profile中的设备,要看哪些设备在硬件Profile中,应到注册表键HKLM/SYSTEM/CurrentControlSet/Hardware Profiles/Current/System/CurrentControlSet下查看。
WINSETUPAPI BOOL WINAPI SetupDiEnumDeviceInfo(
IN HDEVINFO DeviceInfoSet, // 设备信息集合
IN DWORD MemberIndex, // 设备Index
OUT PSP_DEVINFO_DATA DeviceInfoData// 返回设备信息
);
函数本身非常简单,DeviceInfoSet是“设备信息集合”变量,即SetupDiGetClassDevs调用的返回值。
参数MemberIndex是一个从零开始递增的整形变量。调用时应当将其初始值设置为0,循环调用,直到MemberIndex值超出集合范围,函数SetupDiEnumDeviceInfo返回FALSE,可结束递增循环。
上面的函数用来枚举“设备信息集合”中的设备,对应地,还有一个函数用来枚举集合中的设备接口。
WINSETUPAPI BOOL WINAPI
SetupDiEnumDeviceInterfaces(
IN HDEVINFO DeviceInfoSet, // 设备信息集合
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL// 设备成员
IN LPGUID InterfaceClassGuid, // 接口GUID
IN DWORD MemberIndex, // 接口在集合中的Index
OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData// 返回的接口信息
);
DeviceInfoSet是“设备信息集合”变量,即SetupDiGetClassDevs调用的返回值。
DeviceInfoData值很少有人会设置,但如果设置了此值,则函数枚举过程中,将只枚举集合中DeviceInfoData包含的设备接口类。打比方说,DeviceInfoData所代表的设备支持GUID1和GUID2两个设备接口类,则函数在集合中将仅寻找这两类设备接口,而不管其他。
由于此函数用来获取设备接口,而一个集合设置同一个设备中,可包含多种设备接口类,所以参数InterfaceClassGuid用来设置设备接口GUID。
MemberIndex意义与前相同,调用时应将其初始值设置为0,循环调用,直到MemberIndex值超出集合范围使得SetupDiEnumDeviceInterfaces返回FALSE,可结束递增循环。
DeviceInterfaceData中返回设备接口信息。
INF文件的分析,有专门函数。一般不使用普通的文本文档方式分析。首先是打开Inf文件,并生成一个HINF句柄。调用函数SetupOpenInfFile。
然后是打开一个域,使用函数:
接着分析域内容,使用函数:
最后关闭Inf文件,调用函数SetupCloseInfFile。
有专门的一套和INF文件相关的API,他们是SetupAPI的一个子集。列于下:
函数 |
描述 |
InstallHinfSection |
执行指定INF文件中的指定域中指令。这也是Inf文件可执行的原理。 |
SetupCloseInfFile |
释放SetupOpenInfFile打开的HINF句柄。 |
SetupCopyOEMInf |
拷贝INF文件到%windir%/Inf. |
SetupDecompressOr- CopyFile |
拷贝并解压文件 |
SetupFindFirstLine |
搜索并指向域中符合条件的第一行内容 |
SetupFindNextLine |
指向域中的下一行内容,须指明当前行 |
SetupFindNextMatchLine |
搜索域中符合条件的下一行内容,并指向它 |
SetupGetFieldCount |
行中包含几个块,比如”X=1,2”共含3个块。 |
SetupGetFileCompressionInfo |
取得INF文件的压缩信息 |
SetupGetInfDriverStoreLocation |
Retrieves the fully-qualified file name (directory path and file name) of an INF file in the driver store that corresponds to a specified INF file in the system INF file directory or a specified INF file in the driver store. |
SetupGetInfFileList |
Returns a list of the INF files in a specified directory. |
SetupGetInfInformation |
Returns information about an INF file. |
SetupGetIntField |
Obtains the integer value of a specified field in a specified line, in an INF file. |
SetupGetInfPublished Name |
Retrieves the fully-qualified name (directory path and file name) of an INF file in the system INF file directory that corresponds to a specified INF file in the system INF file directory or a specified INF file in the driver store. |
SetupGetLineByIndex |
Returns a pointer to the line associated with a specified index value in a specified section. |
SetupGetLineCount |
Returns the number of lines in the specified section. |
SetupGetLineText |
Retrieves the contents of a specified line from an INF file. |
SetupGetMultiSzField |
Returns multiple strings, starting at a specified field in a line. |
SetupGetSourceFile- Location |
Returns the location of a source file listed in an INF file. |
SetupGetSourceFileSize |
Returns the size of a specified file or a set of files listed in a specified section of an INF file. |
SetupGetSourceInfo |
Retrieves the path, tag file, or description for a source. |
SetupGetStringField |
Retrieves string data from a field in a specified line, in an INF file. |
SetupGetTargetPath |
Determines the target path for the files listed in a specified INF file section. |
SetupInstallFile |
Installs a specified file into a specific target directory. |
SetupInstallFileEx |
Installs a specified file into a specific target directory. The installation is postponed if an existing version of the file is in use. |
SetupInstallFilesFrom- InfSection |
Queues the files in a specified INF file section for copying. (Same as SetupQueueCopySection.) |
SetupInstallFromInfSection |
Performs the directives specified in an INF DDInstall section. |
SetupInstallServices FromInfSection |
Performs service installation and deletion operations as specified in an INF DDInstall.Services section. |
SetupOpenAppendInfFile |
Opens an INF file and appends it to an existing INF handle. |
SetupOpenInfFile |
Opens an INF file and returns a handle to it. |
SetupOpenMasterInf |
Opens the master INF file that contains file and layout information for files shipped with the operating system. |
SetupQueryInfFile Information |
Returns the name of one of the constituent INF files of a specified INF file. |
SetupQueryInfVersion- Information |
Returns the version number of one of the constituent INF files of a specified INF file. |
SetupSetDirectoryId |
Assigns a directory ID (DIRID) to a specified directory. |
SetupUninstallOEMInf |
Uninstalls a specified INF file, and deletes the associated .pnf and .cat files, if they exist. |
SetupVerifyInfFile |
Verifies that a digitally-signed INF file has not been modified. (Windows XP and later.) |
使用上面讲到的技术,结合一些界面设备,就得到了光盘软件DrvInst 1.0。此软件的目地就是实现上述三个功能:软件安装、更新、删除。下面介绍DrvInst的使用界面。
图1主界面
上图是开始界面,含有软件介绍,用户可选择“安装”或“删除”两种功能。
图2 选择设备ID
上图中,在编辑框中输入搜索路径。可直接手动输入并回车;也可通过“选择”按钮定位到指定目录。此后,“选择文件”列表框中将显示此路径下的最多50个安装文件。文件信息也将被显示,包括:驱动版本、提供者、数字签名、类名。用户选择一个文件后点击“下一步”安装。
图3 设备驱动更新
上图显示“安装结果”,以及成功状态下的“设备更新”功能。安装结果中显示了驱动安装状态。存在三种可能状态:系统相同、成功、失败。系统相同说明系统中完全一样的文件已被安装过,不能重复安装;成功说明安装成功;失败说明无法安装。系统相同和成功两种状态下,都会显示和此安装文件相对应的由系统创建的OEM Inf文件名,如上图中的oem105.inf,他被创建于Windows/Inf目录下,用户可手动到此目录中检查一下,是否有此文件存在,并且此文件与原文件的内容应当在二进制级别上完全相同。
成功状态下,软件将重新检索系统,如查询到系统中业已存在刚才安装的驱动文件所包含的设备(根据设备ID),则将它们列于“设备更新”中,供用户更新。这些被找到的设备,已经被安装过驱动,但其版本一定不同。用户可选择一个或多个设备,默认情况下,所有设备都被选中,点击“更新”按钮更新。
如果有设备尚未安装,则此时应将设备连接到系统中开始设备安装。如果驱动文件有数字签名,则无需用户干涉,安装会优先以服务端安装方式“暗地”完成;否则由于系统的安全策略,需用户交互。安装结束后,打开设备管理器,查看是否正确安装。
图4 设备删除
在开始页面中选择“删除驱动”,下一步进入上图界面。在“设备ID”编辑框中输入相应设备ID,回车或点击“确定”按钮,将在设备列表中列出所有的设备。可仅输入设备ID的一部分,这样可以列出更多的设备。比如输入“USB/”将检索到系统中的所有USB设备。列出的设备不仅包括连接设备,也包括当前未连接设备。列出设备会显示“连接”或“未连接”状态。用户可选择一个或多个设备,默认情况下所有设备都被选择,点击“删除”按钮开始删除。删除任务结束后将弹出一个对话框告知完成情况。此时再点击上方的“确认”按钮,由于部分内容已不存在,设备列表中的内容将改变。