Windows 驱动实例分析系列:libwdi 驱动分析 - examples 篇(三)

子文档三:Zadig 核心架构与主程序分析

zadig.c 是 Zadig 工具的主程序,它是一个完整的 Windows GUI 应用程序,使用原生 Win32 API 构建,不依赖 MFC 或 .NET Framework。Zadig 的主要功能是提供一个用户友好的界面,让用户选择 USB 设备并安装相应的驱动程序。其代码量约 2000 行,是 libwdi 最复杂也最完整的应用示例。

整体架构

Zadig 采用经典的 "事件驱动 + 模态对话框" 模式。其核心是一个主对话框(MAIN_DIALOG),所有控件(下拉列表、按钮、编辑框、日志窗口等)都放置在此对话框上。主窗口过程 main_callback 处理所有 Windows 消息,包括控件通知、设备变化事件、自定义消息等。

关键数据结构与全局状态

Zadig 使用大量全局变量管理应用程序状态,这些变量在 zadig.c 顶部声明,包括:

  • struct wdi_device_info *device, *list:当前选中的设备和完整设备链表。
  • struct wdi_options_*:多个 options 结构体,用于配置 libwdi 的行为。
  • int current_device_index:下拉列表中的当前选中项索引。
  • BOOL advanced_mode:是否显示高级选项(日志窗口、文件夹浏览等)。
  • BOOL create_device:是否处于"手动创建设备"模式(即不通过枚举,而是手动输入 VID/PID)。
  • enum wcid_state has_wcid:当前设备是否支持 WCID。
  • UINT64 target_driver_version:目标驱动版本,用于比较并提示升级/降级。

全局状态变量使得 UI 状态与底层逻辑紧密关联,但也增加了代码的耦合度。Zadig 通过精心组织的消息处理来维护状态一致性。

主窗口初始化流程

main_callback 处理 WM_INITDIALOG 时执行以下关键步骤:

  1. 调用 init_dialog:该函数完成所有控件的创建、字体设置、图标加载、工具提示创建等。
  2. 调用 parse_ini :读取 zadig.ini 配置文件,应用用户自定义的默认选项(如默认驱动类型、日志级别、高级模式等)。
  3. 调用 set_loglevel:根据配置设置日志级别。
  4. 调用 set_default_driver:检测系统支持的驱动类型,选择合适的默认驱动。
  5. 调用 toggle_advanced:根据配置显示或隐藏高级控件。
  6. 发送 UM_REFRESH_LIST 消息:触发设备列表的初始枚举和显示。

设备枚举与显示

设备列表的刷新由 UM_REFRESH_LIST 消息驱动。其处理逻辑为:

  • 调用 wdi_create_list 获取设备链表。
  • 调用 display_devices 将设备描述填充到下拉列表(IDC_DEVICELIST)中,并将设备结构体指针作为 itemdata 存储,便于后续快速检索。
  • 若设备列表为空,则禁用"编辑描述"和"安装"按钮。
  • 自动选择当前设备(基于 current_device_hardware_id 或默认选择第一个)。

设备选择与信息显示

当用户从下拉列表中选择设备时,CBN_SELCHANGE 事件触发以下操作:

  • 通过 ComboBox_GetItemData 获取对应的 wdi_device_info 指针。
  • 更新 device 全局变量。
  • 读取 VID、PID、MI、驱动名称、驱动版本等信息,并显示在对应的静态文本和编辑框中。
  • 调用 wdi_get_vendor_name 解析 VID 对应的厂商名称,若无法解析则显示"提交厂商"按钮(IDC_VID_REPORT),引导用户向 USB ID 仓库提交数据。
  • 检测设备的 compatible_id 是否以 USB\MS_COMP_ 开头,判断是否为 WCID 设备,并相应地显示 WCID 状态图标。
  • 根据当前设备的驱动类型和版本,计算"安装"、"替换"、"升级"、"降级"、"重装"等按钮动作,并更新 UI 提示。

安装流程

当用户点击"安装"按钮(IDC_INSTALL)时,主程序调用 install_driver 函数,其流程为:

  1. 若处于"手动创建设备"模式,从编辑框中读取描述、VID、PID、MI,构造一个临时的 wdi_device_info 对象。
  2. 调用 wdi_prepare_driver 准备驱动文件。
  3. 若成功,调用 wdi_install_driver 执行安装。
  4. 根据返回值显示成功/失败消息框,并刷新设备列表(PostMessage(WM_DEVICECHANGE))以反映驱动状态的变化。

安装过程中,installation_running 全局变量被设为 TRUE,禁止用户在安装过程中进行其他操作(如切换设备、修改选项),避免干扰。

设备热插拔处理

Zadig 通过处理 WM_DEVICECHANGE 消息来响应 USB 设备的插入和拔出。由于该消息可能被频繁触发,Zadig 采用 "延迟通知" 策略:

  • 首次收到 WM_DEVICECHANGE 时,创建一个后台线程,该线程等待 NOTIFICATION_DELAY(1000ms)后发送自定义消息 UM_DEVICE_EVENT 回到主线程。
  • 在主线程收到 UM_DEVICE_EVENT 后,刷新设备列表。若当前处于"手动创建"模式,则弹出提示询问用户是否放弃修改并刷新。

这种设计避免了在设备快速插拔时多次刷新 UI,同时也保证了当用户插入一个新设备后,界面能及时更新。

高级功能菜单

Zadig 提供了丰富的菜单选项,包括:

  • 设备 :创建新设备(手动输入 VID/PID)、打开预设配置文件(.cfg)。
  • 选项:高级模式、列出所有设备、忽略集线器、生成 CAT、签名 CAT、日志级别选择。
  • 帮助:在线帮助、检查更新、关于。

这些菜单项通过 WM_COMMAND 处理,调用相应的功能函数(如 toggle_advanced、toggle_driverless 等)。


相关推荐
硫酸锌012 小时前
在手机上运行Python增量备份手机数据到PC电脑
android·windows·python
java_logo3 小时前
Docker 部署 dockurr/windows:轻松搭建浏览器可控 Windows 虚拟机
运维·windows·docker·容器·虚拟机·kvm·轩辕镜像
I Am a robert girl4 小时前
打破音频生态壁垒:用 WinAirCast 把 Windows 声音塞进 HomePod
windows·音视频·跨平台开发·音频串流·airplay 2·homepod
Zhou1411364 小时前
SpringMVC_02_注解开发实战
开发语言·windows·python
额额额对了6 小时前
嵌入式 ADC 从入门到实战:基于 i.MX6ULL 的裸机驱动开发
驱动开发·嵌入式硬件·arm
Code Man6 小时前
实现 Android 字符设备驱动
android·驱动开发·lineageos
sukalot6 小时前
Windows 驱动实例分析系列:libwdi 驱动分析 - examples 篇(四)
windows·驱动开发
WangWei_CM6 小时前
Windows 会话、Session 0 与进程 Token 隔离身份
windows
波力海苔夹心脆6756 小时前
C# 海康威视摄像头二次开发入门:HCNetSDK 登录、实时预览、云台控制、录像与抓图(WinForms 实战)
开发语言·windows·经验分享·tcp/ip·c#