libusb-win32 应用层源码分析(第三篇):安装工具、过滤器管理、注册表操作与动态加载
1. 引言
本篇聚焦于 libusb-win32 的系统集成 与部署机制 。用户态库不仅提供 USB 传输 API,还包含一套完整的工具链,用于安装/卸载内核驱动、管理设备/类过滤驱动,以及操作 Windows 注册表。此外,还提供了运行时动态加载机制(libusb_dyn.c),便于应用程序延迟绑定。
核心代码文件:
registry.c/registry.h:注册表底层操作封装。install.c:核心安装逻辑(命令行、服务、INF 处理)。install_filter.c:命令行过滤驱动管理入口。install_filter_win.c:图形化过滤驱动管理向导。libusb_dyn.c:动态加载libusb0.dll的代理层。
2. 注册表操作模块(registry.c)
该模块直接与 Windows 注册表交互,管理类过滤驱动(Class Filters)和设备过滤驱动(Device Filters)。
2.1 关键数据结构
filter_class_t:表示一个设备类(通过 GUID 或名称标识),包含UpperFilters/LowerFilters的 MULTI_SZ 字符串。filter_device_t:表示一个具体设备(通过硬件 ID 或实例 ID 标识),可包含上/下过滤驱动列表。filter_context_t:聚合所有过滤操作上下文,用于install.c中的命令解析和执行。
2.2 MULTI_SZ 字符串操作
Windows 注册表中的多字符串(REG_MULTI_SZ)以双 null 结尾。registry.c 提供了一系列工具函数:
usb_registry_mz_string_size:计算多字符串总长度。usb_registry_mz_string_find:查找是否存在指定驱动名(不区分大小写)。usb_registry_mz_string_insert:插入新驱动名(追加到末尾)。usb_registry_mz_string_remove:移除指定驱动名(自动压缩内存)。usb_registry_mz_string_lower:转小写以进行比较。usb_registry_mz_to_sz:将 MULTI_SZ 转换为逗号分隔的字符串(用于显示)。
2.3 类过滤驱动操作
- 插入 (
usb_registry_insert_class_filter):- 遍历
filter_context->class_filters。 - 读取该类的
UpperFilters值。 - 若
libusb0不在其中,则插入并写回注册表。 - 标记
class_filters_modified = TRUE。
- 遍历
- 移除 (
usb_registry_remove_class_filter):- 类似地查找并移除
libusb0。 - 若移除后为空,则删除该注册表值。
- 类似地查找并移除
- 类 GUID 路径为
SYSTEM\CurrentControlSet\Control\Class\{GUID}。
2.4 设备过滤驱动操作
usb_registry_insert_device_filters:- 使用
SetupDiGetClassDevs枚举所有 USB 设备。 - 对每个设备,通过硬件 ID 或设备实例 ID 匹配
filter_context->device_filters。 - 若匹配,则修改
UpperFilters或LowerFilters,添加libusb0。 - 删除
SurpriseRemovalOK注册表项(确保设备可被重启)。 - 必要时重启设备。
- 使用
usb_registry_remove_device_filter:- 枚举设备,若匹配则从
UpperFilters/LowerFilters中移除libusb0。 - 支持
--all-devices开关全量移除。
- 枚举设备,若匹配则从
2.5 硬件 ID 解析
usb_registry_fill_filter_hwid:从硬件 ID 字符串(如USB\VID_1234&PID_5678&REV_0001)中提取 VID、PID、MI(接口号)、REV。usb_registry_match_filter_device:基于 VID/PID/MI/REV 或设备实例 ID 进行精确匹配,支持通配(如 MI = -1 表示任意接口)。
2.6 设备状态控制
usb_registry_restart_device/stop_device/start_device:通过DIF_PROPERTYCHANGE触发设备重启/停止/启动。usb_registry_restart_all_devices:遍历所有 USB 设备,重启根集线器(通常用于强制刷新驱动绑定)。
3. 核心安装逻辑(install.c)
这是安装工具集的主模块,支持命令行(install-filter.exe)和图形化(install-filter-win.exe)两种前端。
3.1 命名管道导出函数(rundll32 兼容)
为方便安装程序调用,库导出了多个 CALLBACK 函数,可由 rundll32.exe 直接调用:
usb_install_service_np_rundll:安装驱动服务。usb_uninstall_service_np_rundll:卸载驱动服务。usb_install_driver_np_rundll:安装指定 INF 文件。usb_touch_inf_file_np_rundll:破坏 INF 的数字签名(用于绕过系统驱动保护,仅在特殊情况下使用)。usb_install_np_rundll:通用过滤驱动安装入口。
3.2 服务管理(usb_service_*)
usb_service_create/delete/stop:- 动态加载
advapi32.dll。 - 使用
OpenSCManager、CreateService、DeleteService等 API。 - 驱动服务名固定为
libusb0,显示名包含版本号。 - 启动类型为
SERVICE_DEMAND_START(按需启动)。
- 动态加载
3.3 INF 文件安装(usb_install_inf_np)
- 使用
SetupCopyOEMInf将 INF 复制到系统 INF 目录。 - 解析 INF 的
[Manufacturer]和[Devices]节,提取硬件 ID。 - 调用
UpdateDriverForPlugAndPlayDevices更新匹配设备的驱动。 - 对于非存在设备(
CR_NO_SUCH_DEVINST),设置CONFIGFLAG_REINSTALL标志,使其在下次插入时自动安装。
3.4 过滤驱动上下文解析(usb_install_parse_filter_context)
- 使用
CommandLineToArgvW解析命令行。 - 识别命令:
list,install,uninstall。 - 识别开关:
--all-classes(-ac):操作所有类。--device-classes(-dc):仅操作 USB 枚举器中的类。--class=<GUID/name>(-c=):指定单个类。--device=<hwid>(-d=):指定单个设备。--device-id=<devinst>(-di=):通过设备实例 ID 指定。--inf=<file>(-f=):操作 INF 文件。--all-devices(-ad):移除所有设备过滤驱动。--prompt=/--wait=:交互式提示。
- 构建
filter_context_t结构,供后续执行。
3.5 安装/卸载执行流程(usb_install_console)
FM_INSTALL:- 若指定了类/设备过滤,调用
usb_registry_get_usb_class_keys和usb_registry_get_all_class_keys获取所有相关类。 - 调用
usb_install_service:创建驱动服务、插入类/设备过滤驱动。 - 若指定了 INF,调用
usb_install_inf_np安装设备驱动。
- 若指定了类/设备过滤,调用
FM_REMOVE:- 调用
usb_uninstall_service:移除类/设备过滤驱动、删除服务。 - 对指定的 INF,调用
usb_install_inf_np(remove_mode=TRUE)尝试回滚驱动。
- 调用
FM_LIST:- 枚举所有类,并显示类 GUID、名称、以及当前过滤驱动列表(上/下)。
- 显示设备名称、硬件 ID、实例 ID 及过滤驱动列表。
3.6 图形化进度窗口
usb_install_window创建自定义进度对话框。- 使用 RichEdit 控件显示实时日志,支持颜色区分(错误红色、警告橙色)。
- 自定义进度条使用
GradientFill绘制渐变效果。 - 通过
_beginthread在后台执行实际安装操作,主窗口保持响应。 - 使用互斥信号量(
install_lock_sem_name)防止多个安装实例同时运行。
4. 过滤驱动管理工具
4.1 命令行版本(install_filter.c)
- 简单的
main入口,调用usb_install_npW(NULL, NULL, GetCommandLineW(), 1)。 - 将完整命令行传递给
install.c处理。
4.2 图形化向导(install_filter_win.c)
- 两个对话框:
- 对话框 0:选择操作(安装设备过滤 / 移除设备过滤 / 移除所有设备过滤)。
- 对话框 1 :显示设备列表(通过
ListView),用户选择目标设备。
- 设备发现 :使用
SetupDiGetClassDevs枚举 USB 设备。- 对于安装模式:显示未绑定
libusb0过滤驱动的设备。 - 对于移除模式:显示已绑定
libusb0过滤驱动的设备。 - 自动跳过 USB 集线器和根集线器。
- 对于安装模式:显示未绑定
- 热插拔支持 :注册
GUID_DEVINTERFACE_USB_HUB和GUID_DEVINTERFACE_USB_DEVICE设备通知,收到WM_DEVICECHANGE时自动刷新列表。 - 选择设备后,调用
usb_install_npA执行具体操作,并弹出成功/失败消息框。
5. 动态加载模块(libusb_dyn.c)
该模块提供了一种延迟绑定 机制,允许应用程序在运行时决定是否加载 libusb0.dll,而不是在编译时静态链接。
5.1 函数指针表
- 为所有 libusb API 定义了静态函数指针(如
_usb_open,_usb_bulk_read等),初始为NULL。
5.2 usb_init() 的特殊实现
- 调用
LoadLibrary("libusb0.dll")。 - 若成功,使用
GetProcAddress获取每个导出函数的地址。 - 若某个函数缺失(如旧版本 DLL),对应指针保持
NULL。 - 最后调用
if (_usb_init) _usb_init(),即如果 DLL 中存在usb_init则调用。
5.3 所有 API 包装
- 每个公共 API(如
usb_bulk_read)检查对应函数指针是否非空:- 若非空,调用之。
- 若为空,返回
-ENOFILE(或对指针返回NULL)。
5.4 使用场景
- 应用程序可在调用
usb_init前检查libusb0.dll是否存在,若不存在则给出友好提示。 - 支持多个版本的
libusb0.dll共存,运行时决定使用哪个。 - 注意 :
libusb_dyn.c是独立的,与windows.c中的实现互斥 。通常发布版本使用windows.c直接编译进 DLL,而libusb_dyn.c用于构建代理库(如libusb_dyn.dll或静态库),供第三方软件使用。
6. 技术亮点与安全考虑
- 原子性操作 :过滤驱动的插入/移除伴随
SurpriseRemovalOK的删除,确保设备必须重启以生效。 - 权限检查 :
usb_install_admin_check验证当前进程是否为管理员,非管理员拒绝操作。 - WoW64 检测 :
usb_install_iswow64检测 32 位进程是否运行在 64 位系统上,并提示使用正确的架构版本。 - 幂等性:插入过滤驱动时先检查是否已存在,避免重复添加。
- 回滚支持 :移除设备过滤时,若匹配到设备,会尝试恢复设备状态;INF 卸载支持
DiRollbackDriver。
7. 总结
本篇揭示了 libusb-win32 强大的系统集成能力:
- 通过
registry.c精细操控 Windows 设备类和设备过滤驱动。 install.c提供了一个统一的命令行/图形化前端,支持服务安装、INF 部署、过滤驱动管理的全生命周期。- 动态加载模块
libusb_dyn.c增强了部署灵活性,允许应用按需加载 USB 功能。