【问题标题】:don't get __InstanceOperationEvent when disablingqenabling some devices禁用某些设备时不获取 __InstanceOperationEvent
【发布时间】:2012-02-27 15:36:26
【问题描述】:

我想在插入/移除/启用/禁用 USB 设备时收到通知。 我正在为Win32_USBControllerDevice 注册“__InstanceOperationEvent”。

问题是,虽然我收到了所有设备的插入/删除通知。 我仅获得 USB 存储设备的启用/禁用事件。

我做错了什么?

提前致谢

【问题讨论】:

    标签: usb wmi


    【解决方案1】:

    如果不提供代码示例或告诉我们您使用的语言,您可能很难理解您在说什么。

    Win32_USBController 类是 Win32_PnPEntity 类的关联者,该类具有所有 USB 设备的实例,无论其类型如何。因此,此类的__InstanceOperationEvent 确实为所有设备提供通知,而不仅仅是 USB 存储设备。更恰当地说,它适用于任何 PnP 兼容的 USB 设备。

    以下脚本是用 VBScript 编写的概念点。当设备连接或断开连接时,它将通知您所有 USB 组件。我使用 USB 存储设备、USB 鼠标和键盘以及我身边的各种其他设备进行了测试。他们都工作了。我在 Vista x64 上进行了测试,但这应该适用于任何版本的 Windows。

    示例:

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    
    Set colEvents = objWMIService.ExecNotificationQuery _
        ("Select * From __InstanceOperationEvent Within 1 " _
            & "Where TargetInstance Isa 'Win32_USBControllerDevice'")
    
    While True
        Set objEvent = colEvents.NextEvent
    
        Select Case objEvent.Path_.Class
        Case "__InstanceCreationEvent"
            strOutput = "Device inserted:" & vbCr
        Case "__InstanceDeletionEvent"
            strOutput = "Device removed:" & vbCr
        Case Default
            strOutput = objEvent.Path_.Class & vbCr
        End Select
    
        strDeviceName = objEvent.TargetInstance.Dependent
        strDeviceName = Replace(strDeviceName, Chr(34), "")
        arrDevicePart = Split(strDeviceName, "=")
        strDeviceName = arrDevicePart(1)
    
        Set colUSBDevices = objWMIService.ExecQuery _
            ("Select * From Win32_PnPEntity Where DeviceID = '" & strDeviceName & "'")
        For Each objUSBDevice in colUSBDevices
            strOutput = strOutput & objUSBDevice.Description & vbCr
        Next
    
        WScript.Echo strOutput
    Wend
    

    确定何时启用或禁用设备是类似的,但有一些明显的区别。您将需要使用 Win32_PnPEntity 类,它基本上是所有已安装 PnP 设备的枚举。您需要关注每个实例的 ConfigManagerErrorCode 属性。这提供的信息与您在设备管理器的设备状态部分中找到的信息相同。您可以看到为什么在任何给定设备上观看此属性很有用。当设备更改为显示正常操作的代码 (0) 时,我们可以安全地假设设备已启用。当此代码更改为代码 22 时,我们知道设备已被禁用。 (所有其他代码都表示错误状态。)__InstanceModificationEvent 是监视Win32_PnPEntity 类的任何实例中的更改的好选择。

    如果您对可能的错误代码感兴趣,可以在脚本开头附近输入WScript.Echo 语句,它会在其中枚举所有可能的值。

    示例:

    Const wbemFlagUseAmendedQualifiers = &H20000
    
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    
    Set objPnPEntityClass = objWMIService.Get("Win32_PnPEntity", wbemFlagUseAmendedQualifiers)
    arrValues = objPnPEntityClass.properties_("ConfigManagerErrorCode").qualifiers_("values")
    valueMap = objPnPEntityClass.properties_("ConfigManagerErrorCode").qualifiers_("valuemap")
    
    WScript.Echo "Gathering Device Manager error codes..."
    Set dictErrorCodes = CreateObject("Scripting.Dictionary")
    For i = 0 to Ubound(arrValues)
        dictErrorCodes.add valueMap(i), arrValues(i)
        '  0, This device is working properly.
        ' 22, This device is disabled.
    Next
    
    Set objPnPEntityClass = Nothing
    
    WScript.Echo "Setting up event notification..."
    Set colEvents = objWMIService.ExecNotificationQuery _
        ("Select * From __InstanceModificationEvent Within 1 " _
            & "Where TargetInstance Isa 'Win32_PnPEntity'")
    
    WScript.Echo "Waiting..."
    While True
        Set objEvent = colEvents.NextEvent
        Set objDevice = objEvent.TargetInstance
    
        Select Case objDevice.ConfigManagerErrorCode
        Case 0      ' This device is working properly.
            strOutput = objDevice.Caption & " is working properly." & vbCr
        Case 22     ' This device is disabled.
            strOutput = objDevice.Caption & " has been disabled." & vbCr
        Case Default
            strDeviceStatus = arrValues(objDevice.ConfigManagerErrorCode)
            strOutput = "(" & objDevice.Caption & ") " &  strDeviceStatus & vbCr
        End Select
    
        WScript.Echo strOutput
    Wend
    

    【讨论】:

    • 感谢您的回答!我确实收到所有 USB 插入/移除的通知。但对于某些设备,当它们被禁用/启用时,我没有收到事件。
    • @user844541 你的意思是在不移除设备的情况下启用/禁用?你能给我一个设备的例子吗?我不确定我是否理解您的意思。
    • 我们以贝尔金无线网络适配器为例。插入设备后,我会收到一个事件并做任何我需要的事情。但如果设备被禁用,然后用户通过设备管理器启用它,我不会收到任何事件。
    • 我明白你在说什么。那是因为您没有为此注册正确的活动。即使设备被“禁用”,它仍然是连接的。让我看看我是否可以为此确定合适的事件。
    • @user844541 好的,我搞定了。我已经在上面的帖子中添加了相关代码。
    【解决方案2】:

    Win32_PnPEntity 确实适用于我的 USB 指纹扫描仪设备。 但是它不会选择未安装驱动程序的设备的事件。我也给出了我的代码,可能我的代码有问题。

    static void Main(string[] args)
        {
            WqlEventQuery weqQuery = new WqlEventQuery();
            weqQuery.EventClassName = "__InstanceOperationEvent";
            weqQuery.WithinInterval = new TimeSpan(0, 0, 3);
            weqQuery.Condition = @"TargetInstance ISA 'Win32_PnPEntity'";
    
            ManagementEventWatcher m_mewWatcher = new ManagementEventWatcher(weqQuery);
            m_mewWatcher.EventArrived += new EventArrivedEventHandler(m_mewWatcher_EventArrived);
    
            m_mewWatcher.Start();
            m_mewWatcher1.Start();
            Console.ReadLine();
        }
        static void m_mewWatcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
    
            bool bUSBEvent = false;
    
            foreach (PropertyData pdData in e.NewEvent.Properties)
            {
                try
                {
                    ManagementBaseObject mbo = (ManagementBaseObject)pdData.Value;
                    if (mbo != null)
                    {
                        foreach (PropertyData pdDataSub in mbo.Properties)
                        {
                            Console.WriteLine("pdDataSub.Name= " + pdDataSub.Name + " and pdDataSub.Value.ToString() = " + (pdDataSub.Value == null ? "" : pdDataSub.Value));
                        }
                    }
                }
                catch (Exception ex)
                {
                }
            }
        }
    

    【讨论】:

    • 谢谢!我去看看。
    猜你喜欢
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    • 2017-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多