Поймать USB-штекер и отключить событие System.InvalidCastException - PullRequest
0 голосов
/ 01 октября 2018

Я пытаюсь обнаружить вставку USB-устройства и удалить его с помощью приложения C # для WinForm:

 public Form1()
    {
        InitializeComponent();
        USB();
    }

, затем:

private void USB()
{
     WqlEventQuery weqQuery = new WqlEventQuery();
     weqQuery.EventClassName = "__InstanceOperationEvent";
     weqQuery.WithinInterval = new TimeSpan(0, 0, 3);
     weqQuery.Condition = @"TargetInstance ISA 'Win32_DiskDrive'";  
     var m_mewWatcher = new ManagementEventWatcher(weqQuery);
     m_mewWatcher.EventArrived += new EventArrivedEventHandler(m_mewWatcher_EventArrived);
     m_mewWatcher.Start();           
}

и:

static void m_mewWatcher_EventArrived(object sender, EventArrivedEventArgs e)
    {
        bool bUSBEvent = false;
        foreach (PropertyData pdData in e.NewEvent.Properties)
        {
            ManagementBaseObject mbo = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;
           // ManagementBaseObject mbo = (ManagementBaseObject)pdData.Value;
            if (mbo != null)
            {
                foreach (PropertyData pdDataSub in mbo.Properties)
                {
                    if (pdDataSub.Name == "InterfaceType" && pdDataSub.Value.ToString() == "USB")
                    {
                        bUSBEvent = true;
                        break;
                    }
                }

                if (bUSBEvent)
                {
                    if (e.NewEvent.ClassPath.ClassName == "__InstanceCreationEvent")
                    {
                        MessageBox.Show ("USB was plugged in");
                    }
                    else if (e.NewEvent.ClassPath.ClassName == "__InstanceDeletionEvent")
                    {
                        MessageBox.Show("USB was plugged out");
                    }
                }
            }
        }
    }

Но я получил исключение с ManagementBaseObject mbo = (ManagementBaseObject)pdData.Value;, когда обнаружил изменение USB:

Исключение типа 'System.InvalidCastException' произошло в Controller.exe, но не было обработано в коде пользователя

Дополнительная информация: Невозможно привести объект типа 'System.UInt64' к типу 'System.Management.ManagementBaseObject'.

edit:

using System;
using System.Windows.Forms;
using System.Management;

namespace test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            WqlEventQuery query = new WqlEventQuery()
            {
                EventClassName = "__InstanceOperationEvent",
                WithinInterval = new TimeSpan(0, 0, 3),
                Condition = @"TargetInstance ISA 'Win32_DiskDrive'"
            };

            using (ManagementEventWatcher MOWatcher = new ManagementEventWatcher(query))
            {
                MOWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent);
                MOWatcher.Start();
            }
        }

        private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
        {
            using (ManagementBaseObject MOBbase = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value)
            {
                bool DriveArrival = false;
                string EventMessage = string.Empty;
                string oInterfaceType = MOBbase.Properties["InterfaceType"]?.Value.ToString();

                if (e.NewEvent.ClassPath.ClassName.Equals("__InstanceDeletionEvent"))
                {
                    DriveArrival = false;
                    EventMessage = oInterfaceType + " Drive removed";
                }
                else
                {
                    DriveArrival = true;
                    EventMessage = oInterfaceType + " Drive inserted";
                }
                EventMessage += ": " + MOBbase.Properties["Caption"]?.Value.ToString();
                this.BeginInvoke((MethodInvoker)delegate { this.UpdateUI(DriveArrival, EventMessage); });
            }
        }

        private void UpdateUI(bool IsDriveInserted, string message)
        {
            if (IsDriveInserted)
            {
                this.label1.Text = message;
            }             
            else
            {
                this.label1.Text = message;
            }                
        }
    }
}

1 Ответ

0 голосов
/ 02 октября 2018

Здесь ManagementEventWatcher инициализируется для события Button.Click().Конечно, вы можете инициализировать его в другом месте.Например, в Form.Load().

Подписано событие ManagementEventWatcher.EventArrived , для делегата установлено значение private void DeviceInsertedEvent().Процедура наблюдения начинается с использования ManagementEventWatcher.Start () (MOWatcher.Start();)

Когда событие уведомляется, EventArrivedEventArgs e.NewEvent . Properties["TargetInstance"].Value будет установлен в ManagementBaseObject , который будет ссылаться на Win32_DiskDrive класс WMI / CIM.
Прочтите документацию, чтобы узнать, какая информация доступнав этом классе.

Это событие не повышается в потоке пользовательского интерфейса.Чтобы уведомить основной интерфейс пользовательского интерфейса о природе события, нам нужно .Invoke () метод в этом потоке.

this.BeginInvoke((MethodInvoker)delegate { this.UpdateUI(DriveArrival, EventMessage); });

ЗдесьВызывается метод private void UpdateUI(), делегирующий обновление пользовательского интерфейса методу, который выполняется в потоке пользовательского интерфейса.

Обновление:
Добавлено RegisterWindowMessage () чтобы зарегистрировать QueryCancelAutoPlay , чтобы предотвратить появление окна автозапуска перед нашей формой, воровав фокус.

Визуальный пример результатов:

WMI_EventWatcher

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern uint RegisterWindowMessage(string lpString);

private uint CancelAutoPlay = 0;

private void button1_Click(object sender, EventArgs e)
{
    WqlEventQuery query = new WqlEventQuery() {
        EventClassName = "__InstanceOperationEvent",
        WithinInterval = new TimeSpan(0, 0, 3),
        Condition = @"TargetInstance ISA 'Win32_DiskDrive'"
    };

    ManagementScope scope = new ManagementScope("root\\CIMV2");
    using (ManagementEventWatcher MOWatcher = new ManagementEventWatcher(query))
    {
        MOWatcher.Options.Timeout = ManagementOptions.InfiniteTimeout;
        MOWatcher.EventArrived += new EventArrivedEventHandler(DeviceChangedEvent);
        MOWatcher.Start();
    }
}

private void DeviceChangedEvent(object sender, EventArrivedEventArgs e)
{
    using (ManagementBaseObject MOBbase = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value)
    {
        bool DriveArrival = false;
        string EventMessage = string.Empty;
        string oInterfaceType = MOBbase.Properties["InterfaceType"]?.Value.ToString();

        if (e.NewEvent.ClassPath.ClassName.Equals("__InstanceDeletionEvent"))
        {
            DriveArrival = false;
            EventMessage = oInterfaceType + " Drive removed";
        }
        else
        {
            DriveArrival = true;
            EventMessage = oInterfaceType + " Drive inserted";
        }
        EventMessage += ": " + MOBbase.Properties["Caption"]?.Value.ToString();
        this.BeginInvoke((MethodInvoker)delegate { this.UpdateUI(DriveArrival, EventMessage); });
    }
}


private void UpdateUI(bool IsDriveInserted, string message)
{
    if (IsDriveInserted)
        this.lblDeviceArrived.Text = message;
    else
        this.lblDeviceRemoved.Text = message;
}


[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (CancelAutoPlay == 0)
        CancelAutoPlay = RegisterWindowMessage("QueryCancelAutoPlay");

    if ((int)m.Msg == CancelAutoPlay) { m.Result = (IntPtr)1; }
}
...