如何从我的 Windows 驱动程序代码中区分 devmgmt 的禁用和卸载?

How to distinguish devmgmt's Disable and Uninstall from within my Windows driver code?

我正在研究来自 WDK7 的 Microsoft Toaster 示例代码,我发现了一个微妙的问题。

现在在 Windows 7 上尝试编译的驱动程序(WDM busenum 和 WDM featured1)。

按照 README 的指导,enum -p 1 添加了一个烤面包机设备,然后,我打开设备管理器 (devmgmt),找到该设备,卸载 它。

这将破坏烤面包机 devnode(我相信); 我们可以看到 ToasterDevice01 节点现在从设备管理器中消失了。 !devnode 0 1 表明 toaster devnode 仍然存在,State=DeviceNodeUninitialized (0x301),Previous State=DeviceNodeRemoved (0x312)。

然后,我执行enum -p 1 尝试再次添加设备。但是我收到错误 0x57(ERROR_INVALID_PARAMETER).

我调试了源码,查明原因:buspdo.c没有区分devmgmt的Disable和Uninstall操作。他的代码逻辑是:

问题是,当end-user 从devmgmt 执行卸载时,它遵循禁用路径。现在发生了一些不好的事情:Windows 删除了烤面包机 devnode,但烤面包机总线驱动程序没有破坏相应的 PDO,因此,当下次用户执行 enum -p 1 时,烤面包机总线驱动程序 Bus_PlugInDevice() 指责SerialNo==1 的烤面包机设备已经存在,因此用户请求失败。

顺便说一句:Toaster 的 KMDF 版本出现了类似的问题(今天只试过 static-enumeration 版本)

现在我的问题很清楚了:如何区分禁用和卸载,我应该在总线驱动程序还是子设备驱动程序中进行?也欢迎 KMDF 版本的答案。

现在可以下结论了。我们的客户端驱动程序无法从设备管理器中区分禁用和卸载。这是微软的设计。

要进行区分,需要应用层的帮助。为 child 设备提供 CoInstaller,并且当 CoInstaller 收到 DIF_REMOVE 通知(这是 devmgmt 执行卸载的结果)时,向内核驱动程序发送自定义 IOCTL(例如 IOCTL_UNPLUG_MY_CHILD),以便该内核驱动程序拔出对应的child。