Определить, когда диск смонтирован или изменяет состояние (WM_DEVICECHANGE для WPF)?

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

константин

Ответы на вопрос(4)

вы все равно можете перехватить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);
    }
}
 akonsu22 сент. 2010 г., 20:53
Благодарю. я подозреваю, что это не переносимо, это не будет работать на других операционных системах. Не могли бы вы объяснить, какова цель создания объекта SystemEventIntercept внутри метода OnSourceInitialized и нигде его не использовать?
 Allon Guralnek27 дек. 2012 г., 09:56
+1: как раз то, что мне нужно для обнаружения специализированного USB-устройства, так как ответ на прием будет обнаруживать только устройства хранения. Сначала это решение не работало, пока я не сделалSystemEventIntercept intercept свойство вместо локальной переменной, тогда это работало хорошо. Как локальная переменная (которая никогда не используется), она должна быть собрана почти сразу же.
 Zach Johnson22 сент. 2010 г., 21:14
@akonsu: Да, это решение не переносимо, но я не думаю, что WPF тоже.OnSourceInitialized вызывается, когда основной дескриптор Win32 вашего окна WPF был создан, так что это удобное место для подключения к нему.SystemEventIntercept на самом деле что-то делает, когда он создается, он сразу начинает прослушивать сообщения. Когда вы перехватываетеWM_DEVICECHANGE, вы можете делать все, что вам нужно на// do something комментарий. Мой код является лишь примером, вам, вероятно, придется изменить его в соответствии с вашими потребностями.

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);
            }
        }
    }
}

Решение Вопроса

в своем ответе)

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
        }
    }
}

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

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

Ваш ответ на вопрос