Win32 API 函数以编程方式启用/禁用设备
我正在编写一个小型 C# 应用程序,以便在检测到另一个鼠标设备时禁用设备(我的笔记本电脑触摸板),并在未检测到鼠标时再次启用触摸板。我什至无法在设备管理器中禁用触摸板(它在默认鼠标类驱动程序上运行)。
我正在进入设备驱动程序开发,所以我想也许我可以编写一个小过滤器驱动程序,它只接受 IOCTL 来启用和禁用在设备堆栈上传递鼠标事件消息,并通过原始 PDO 从用户模式获取消息。但是,我问这个问题,有人建议我可以通过 在用户模式下执行此操作SetupDi.. 函数。那真是太好了,因为这种原始 PDO 通信方法是可以使用的 PITA。
我以前只使用过SetupDiGetClassDevs,而且有很多,对 Win32 API 这一部分有更多经验的人可以快速告诉我应该调用哪个来停止/禁用鼠标设备或其界面,或者框架的黑暗角落中是否有某些东西可以执行此操作(也许在 WMI 中?)。
更新 (24/9/09) 我弄清楚了如何使用过滤器驱动程序执行此操作,并将我的操作方法发布在 我原来的问题。我仍然想知道是否可以直接从 Win32 启用或禁用设备,如果可以,如何操作 - 所以我将保留这个问题。
I am writing a small C# app to disable a device (my laptop touchpad) whenever another mouse device is detected, and enable the touchpad again if a mouse is not detected. I am not even able to disable the touchpad in device manager (it is running on the default mouse class driver).
I am getting into device driver development so I thought maybe I could write a little filter driver that would just accept IOCTLs to enable and disable passing mouse event messages up the device stack, and get messages from user mode via a raw PDO. However, I asked that question and somebody has suggested that I can do this in usermode via the SetupDi.. functions. That would be really good, because this raw PDO communication method is a PITA to work with.
I have only used SetupDiGetClassDevs before, and there are so many of them, can someone with more experience with this part of the Win32 API just tell me quickly what one I should call to stop/disable a mouse device or its interface or if there is something somewhere in the dark corners of the framework that will do this (maybe in WMI?).
Update (24/9/09) I figured out how to do this with a filter driver and posted how I did it on my original question. I still want to know if it is possible to enable or disable devices directly from Win32 and if so, how - so I will leave this question open.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以使用SetupDi API 从Win32(因此从C# 通过P/Invoke)启用/禁用设备,但并非所有设备都可以通过这种方式“禁用”。
尝试从 Win32(或 WMI 或调用
SetupDi*
系列函数的任何其他 API)禁用触摸板时,您会遇到的问题是大多数笔记本电脑中的默认鼠标驱动程序使用触摸板(“PS/2 兼容鼠标”)不支持使用SetupDi
API 禁用。我怀疑这可能是因为使用 PS/2 连接器的实际旧鼠标在不连接硬件的情况下无法热拆卸。要验证您是否无法禁用,请进入设备管理器并右键单击您的鼠标驱动程序。如果您看到禁用选项,可以使用SetupDi 来禁用它。如果没有禁用选项,那么您就不走运了...欢迎来到 IOCTL-land!
如果您确实看到禁用选项,则可以使用下面的代码(从我发现的 VB 示例移植到 C# 此处)应该可以让您禁用并重新启用该设备。
这是调用该库的代码:
这是库本身,改编自 这里。
请注意,当您在
int index = GetIndexOfInstance(diSetHandle, diData, instanceId);
行上收到 Index-Out-Of-Bounds 异常时,您可能使用了错误的设备 classGuid 或错误的实例 ID。另请注意,当您在 64 位 Windows 平台上运行此代码时,您在构建应用程序时应该以 64 位平台为目标。否则,即当您的应用程序作为 64 位 Windows 平台上的 32 位进程运行时,您将收到 SetupAPI 错误 InWow64 (ERROR_IN_WOW64)。
当针对 64 位 Windows 平台时,您可能还必须对应用程序的其他部分进行更改,例如在进行指针算术时,以防止溢出。
You can enable/disable devices from Win32 (and hence from C# via P/Invoke) using the SetupDi APIs but not all devices are "disable-able" in this way.
The problem you'll run into trying to disable your touchpad from Win32 (or WMI or any other API which calls down into the
SetupDi*
family of functions) is that the default mouse driver which is in most laptops with a touchpad ("PS/2 compatible mouse") doesn't support being disabled usingSetupDi
API's. I suspect this may be because actual old mice using PS/2 connectors can't be hot-detached without hosing the hardware.To verify that you can't disable, go into Device Manager and right-click on your mouse driver. If you see a disable option, you can use SetupDi to disable it. If no disable option, you're out of luck... welcome to IOCTL-land!
If you do see a disable option, then the code below (ported to C# from a VB sample I found here) should let you disable and re-enable the device.
Here's the code to call the library:
Here's the library itself, adapted from here.
Note that when you get an Index-Out-Of-Bounds exception on the line
int index = GetIndexOfInstance(diSetHandle, diData, instanceId);
, you might have used the wrong classGuid for the device or the wrong instanceId.Also note that when you run this code on a 64-bit Windows platform, you should target the 64-bit platform when you build your application. Otherwise - i.e. when running your application as a 32-bit process on a 64-bit Windows platform - you will get an SetupAPI error InWow64 (ERROR_IN_WOW64).
When targetting a 64-bit Windows platform, you might also have to make changes to other parts of your application, e.g. when doing pointer arithmetic, in order to prevent overflows.
一种方法可能是使用 Windows Management Instrumentation 层。该层中似乎定义了一些与设备相关的类。
One way might be to use the Windows Management Instrumentation layer. There seems to be a few device related classes defined in this layer.
如果您想切换设备启用状态,您可以通过将
SetDeviceEnabled
替换为以下内容来适应 @JustinGrant 的惊人解决方案:In case you wanted to toggle the device enabled status, you can adapt @JustinGrant's amazing solution by replacing
SetDeviceEnabled
with the following:您可以考虑下面提到的Win API
CM_Request_Device_EjectW 函数: CM_Request_Device_Eject 函数准备本地设备实例以进行安全删除。如果设备是可移动的。
CM_Query_And_Remove_SubTreeW 函数: CM_Query_And_Remove_SubTree 函数检查是否可以删除设备实例及其子实例,如果可以,则将其删除。
同样可以在这里找到: CM_Request_Device_EjectW < /a> 和 CM_Query_And_Remove_SubTreeW
You can consider the below mentioned Win APIs
CM_Request_Device_EjectW function: The CM_Request_Device_Eject function prepares a local device instance for safe removal. If the device is removable.
CM_Query_And_Remove_SubTreeW function: The CM_Query_And_Remove_SubTree function checks whether a device instance and its children can be removed and if so, it removes them.
And the same can be found here: CM_Request_Device_EjectW and CM_Query_And_Remove_SubTreeW