ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

windows 驱动实例分析系列: HidHide驱动分析-HidHideClient 篇(下)

windows 驱动实例分析系列: HidHide驱动分析-HidHideClient 篇(下) HidHide 驱动分析 - HidHideClient 篇下黑名单对话框与设备枚举机制一、黑名单对话框的功能定位CBlacklistDlg是主对话框中的设备标签页负责管理黑名单Blacklist——即需要被隐藏的 HID 设备。与白名单的简洁列表不同黑名单采用树形控件TreeCtrl展示设备层级支持对复合设备如 USB 复合手柄进行细粒度控制既可单独隐藏某个子功能如按键、摇杆也可一键隐藏整个物理设备。此外该对话框还提供了状态图标锁定图标表示设备是否被隐藏开锁/关锁/空白。过滤选项“仅显示已连接设备和仅显示游戏设备”方便用户聚焦。总开关启用设备隐藏复选框与驱动 Active 状态联动。二、类结构与成员变量classCBlacklistDlg:publicCDialogEx,publicHidHide::IDropTarget{CHidHideClientDlgm_HidHideClientDlg;HidHide::FriendlyNamesAndHidDeviceInformation m_BlacklistItemData;// 设备信息缓存CTreeCtrl m_Blacklist;// 树形控件HCMNOTIFICATION m_CmNotificationHandle;// PnP 通知句柄HICON m_LockOn,m_LockOff,m_LockBlank;// 状态图标CImageList m_ImageList;// 图标列表CButton m_Filter,m_Gaming,m_Enable;// 过滤与开关控件CStatic m_Guidance;// 提示标签};三、设备枚举与信息采集HID 模块复用黑名单对话框依赖HidHide::HidDevices(bool gamingDevicesOnly)函数获取系统所有 HID 设备的详细信息。该函数实现在共享的HID.cpp中执行以下步骤枚举 HID 设备实例通过SetupDiGetClassDevs(GUID_DEVCLASS_HIDCLASS)获取所有 HID 类设备。获取设备接口路径对每个设备通过SetupDiGetDeviceInterfaceDetail获取符号链接Symbolic Link用于后续打开设备。获取设备属性通过CM_Get_DevNode_Property获取设备实例路径、描述、容器 ID、父设备等。打开设备查询 HID 信息使用CreateFile打开符号链接调用HidD_GetAttributes、HidD_GetProductString、HidP_GetCaps等获取 VID/PID、产品名称、Usage Page/Usage。容器聚合通过DEVPKEY_Device_ContainerId将属于同一物理设备如 USB 复合设备的多个 HID 子设备归为一组构建友好的显示名称FriendlyNamesAndHidDeviceInformation。该过程兼顾了已连接和已断开但残留的设备通过CM_LOCATE_DEVNODE_PHANTOM确保用户能清理历史残留条目。四、初始化与 PnP 通知注册OnInitDialogCM_NOTIFY_FILTER cmNotifyFilter{sizeof(CM_NOTIFY_FILTER),CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES,CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE,0,0};if(autoconstresult{::CM_Register_Notification(cmNotifyFilter,this,OnCmNotificationCallbackStatic,m_CmNotificationHandle)};(CR_SUCCESS!result))THROW_CONFIGRET(result);注册 PnP 设备接口到达通知当新 HID 设备插入时驱动会触发回调OnCmNotificationCallback该回调调用Refresh()刷新树形列表实现热插拔实时更新。五、树形控件填充逻辑Refresh 与 OnUserMessageRefreshRefresh通过PostMessage触发OnUserMessageRefresh在其中执行完整的树重建删除所有节点m_Blacklist.DeleteAllItems()获取当前黑名单FilterDriverProxy().GetBlacklist()返回std::setDeviceInstancePath获取设备列表HidHide::HidDevices(false)返回容器分组数据遍历每个容器判断该容器是否整体黑名单基容器路径在黑名单中判断是否有子设备在黑名单中anyChildEntryBlacklisted判断是否所有子设备都在黑名单中allChildEntryBlacklisted应用过滤条件m_Filter和m_Gaming但若设备已在黑名单中则忽略过滤确保已隐藏设备始终可见。插入父节点设置图标锁定状态和复选框状态。插入子节点每个子设备关联其HidDeviceInformation结构体作为节点数据SetItemData便于后续更新。六、复选框交互与黑白名单同步OnTvnItemChangedTreeBlacklist当用户点击树节点的复选框时OnTvnItemChangedTreeBlacklist被触发。其核心逻辑区分顶级节点和子节点通过GetParentItem判断。顶级节点变化同步修改所有子节点的复选框状态并更新顶级节点图标开锁/关锁。子节点变化若子节点被勾选检查同级所有子节点是否都被勾选若是则自动勾选父节点。若子节点被取消勾选自动取消父节点勾选。构建新黑名单遍历所有节点根据复选框状态收集设备实例路径若父节点被勾选且其所有子设备均为 HID 设备且数量等于容器子设备总数则添加基容器路径实现整体隐藏。否则逐个添加被勾选的子设备路径。同步到驱动FilterDriverProxy().SetBlacklist(deviceInstancePaths)此机制允许用户通过勾选父节点一键隐藏整个复合设备同时也支持精细到单个子功能的隐藏。七、过滤条件与显示优化“仅显示已连接设备”m_Filter当勾选时跳过所有present false的设备除非已在黑名单中。“仅显示游戏设备”m_Gaming当勾选时跳过所有gamingDevice false的设备除非已在黑名单中。gamingDevice的判断依据Usage Page 是否为0x01通用桌面控制且 Usage 为0x04摇杆或0x05游戏手柄或特定的 VID/PID如 Valve Steam 控制器。这一定义覆盖了绝大多数游戏外设。八、PnP 通知回调与线程安全OnCmNotificationCallback运行在系统线程上下文中不能直接操作 UI。因此它仅调用Refresh()而Refresh()通过PostMessage将更新请求放入 UI 线程的消息队列确保线程安全。DWORDCBlacklistDlg::OnCmNotificationCallback(...){if(CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVALcmNotifyAction){Refresh();}return0;}九、启用/禁用总开关OnBnClickedCheckEnableFilterDriverProxy().SetActive(0!(m_Enable.GetCheck()BST_CHECKED));直接同步到驱动控制全局隐藏功能的启用/禁用。当禁用时所有设备对所有应用可见。十、图标与视觉反馈黑名单对话框使用三个图标表达设备状态锁开ICON_LOCK_OFF设备未被隐藏。锁关ICON_LOCK_ON设备被隐藏父节点或子节点被勾选。空白ICON_LOCK_BLANK用于子节点表示其不直接显示锁定状态继承父节点状态。这种图标设计使得用户一眼就能识别设备的隐藏状态提升了可用性。十一、异常处理与资源清理析构函数中调用::CM_Unregister_Notification取消 PnP 通知注册避免悬挂句柄。所有 Windows API 调用均检查返回值失败时抛出异常由顶层处理。十二、与白名单对话框的交互联动虽然两个对话框独立管理各自列表但它们共享同一个FilterDriverProxy实例由主对话框持有。当白名单或黑名单发生变化时驱动立即生效无需用户点击应用按钮实现了所见即所得的配置体验。总结HidHideClient 通过 MFC 框架提供了成熟、可靠的图形化配置界面。白名单对话框支持文件选择和拖放添加黑名单对话框利用树形控件与 PnP 通知实现设备实时管理与精细隐藏。两者通过统一的驱动代理与内核通信构成了用户操作 HidHide 驱动的主要入口。
返回列表