Определить, когда диск смонтирован или изменяет состояние (WM_DEVICECHANGE для WPF)? - PullRequest
2 голосов
/ 22 сентября 2010

Я пишу элемент управления селектором каталогов для WPF и хотел бы добавить / удалить диск из дерева каталогов, когда он монтируется или демонтируется или когда он становится готовым или не готовым (например, пользователь вставляет или удаляет компакт-диск).Я ищу системное событие, похожее на WM_DEVICECHANGE.

konstantin

Ответы [ 4 ]

5 голосов
/ 22 сентября 2010

Даже если вы используете WPF, вы все равно можете перехватить WM_DEVICECHANGE.Вы можете либо присоединиться к существующей оконной процедуре, используя методы обратного вызова WPF, либо использовать System.Windows.Forms.NativeWindow (мой предпочтительный метод, больше контроля и проще, но вам нужно добавить ссылку на System.Windows.Forms.dll)

// in your window's code behind
private static int WM_DEVICECHANGE = 0x0219;

protected override void OnSourceInitialized(EventArgs e)
{
    WindowInteropHelper helper = new WindowInteropHelper(this);
    SystemEventIntercept intercept = new SystemEventIntercept(helper.Handle);
    base.OnSourceInitialized(e);
}

class SystemEventIntercept : System.Windows.Forms.NativeWindow
{
    public SystemEventIntercept(IntPtr handle)
    {
        this.AssignHandle(handle);
    }

    protected override void WndProc(ref Winforms.Message m)
    {
        if (m.Msg == WM_DEVICECHANGE)
        {
            // do something
        }

        base.WndProc(ref m);
    }
}
5 голосов
/ 22 сентября 2010

Я использовал WMI для реализации чего-то подобного (как сказал Ричард в своем ответе)

using System.Management; 
using System;

...

private void SubscribeToCDInsertion()
{
    WqlEventQuery q;
    ManagementOperationObserver observer = new ManagementOperationObserver();

    // Bind to local machine
    ConnectionOptions opt = new ConnectionOptions();
    opt.EnablePrivileges = true; //sets required privilege
    ManagementScope scope = new ManagementScope("root\\CIMV2", opt);

    q = new WqlEventQuery();
    q.EventClassName = "__InstanceModificationEvent";
    q.WithinInterval = new TimeSpan(0, 0, 1);
    // DriveType - 5: CDROM
    q.Condition = @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5";
    var w = new ManagementEventWatcher(scope, q);
    try
    {

       // register async. event handler
       w.EventArrived += new EventArrivedEventHandler(driveInsertEvent);
       w.Start();

    }
    catch (Exception e)
    {
        w.Stop();
    }

}

void driveInsertEvent(object sender, EventArrivedEventArgs e)
{
    // Get the Event object and display it
    PropertyData pd = e.NewEvent.Properties["TargetInstance"];

    if (pd != null)
    {
        ManagementBaseObject mbo = pd.Value as ManagementBaseObject;
        // if CD removed VolumeName == null
        if (mbo.Properties["VolumeName"].Value != null)
        {
            //do something
        }
    }
}

РЕДАКТИРОВАТЬ: я не сам изобрел код, я думаю, что я получил от здесь

2 голосов
/ 23 сентября 2010

приведенный ниже код работает для меня.он подписывается на события DriveType = 2 и DriveType = 5 для обнаружения CD-ROM и USB.Поскольку мне не нужно знать, был ли диск смонтирован или размонтирован, или CD был удален или вставлен, код не проверяет это.для подключений usb e.NewEvent.ClassPath может использоваться для определения того, был ли диск подключен или отключен.

Кроме того, в Интернете я нашел несколько запутанных замечаний о том, что подписка на события только для DriveType = 5 будет обнаруживать подключения USBтакже.у меня это не сработало.

константин


using System;
using System.Management;

namespace consapp
{
    class Program
    {
        static void Main(string[] args)
        {
            const string QUERY = @"select * from __InstanceOperationEvent within 1 where TargetInstance isa 'Win32_LogicalDisk' and (TargetInstance.DriveType=2 or TargetInstance.DriveType=5)";

            Program p = new Program();

            ManagementEventWatcher w = new ManagementEventWatcher(new WqlEventQuery(QUERY));

            w.EventArrived += new EventArrivedEventHandler(p.OnWMIEvent);
            w.Start();

            Console.ReadKey();

            w.Stop();
        }

        public void OnWMIEvent(object sender, EventArrivedEventArgs e)
        {
            PropertyData p = e.NewEvent.Properties["TargetInstance"];

            if (p != null)
            {
                ManagementBaseObject mbo = p.Value as ManagementBaseObject;

                PropertyData deviceid = mbo.Properties["DeviceID"];
                PropertyData drivetype = mbo.Properties["DriveType"];

                Console.WriteLine("{0}-{1}:{2}", deviceid.Value, drivetype.Value, e.NewEvent.ClassPath);
            }
        }
    }
}

1 голос
/ 22 сентября 2010

Вы могли бы:

  • Использование событий WMI и WMI для обнаружения аппаратных изменений.
  • Используйте скрытое окно WinForms с переопределением метода WinProc, чтобы выбрать WM_DEVICECHANGE.
...