检测何时安装驱动器或更改状态(WMF的WM_DEVICECHANGE)?

时间:2010-09-22 18:12:23

标签: .net wpf

我正在为WPF编写一个目录选择器控件,我想在挂载或卸载时或者当它准备好或没有准备好时(例如用户插入或删除CD)从目录树中添加/删除驱动器)。我正在寻找类似于WM_DEVICECHANGE的系统事件。

康斯坦丁

4 个答案:

答案 0 :(得分:5)

即使您使用的是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);
    }
}

答案 1 :(得分:5)

我使用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
        }
    }
}

编辑:我自己没有发明代码,我想我是从here

得到的

答案 2 :(得分:2)

以下代码对我有用。它订阅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);
            }
        }
    }
}

答案 3 :(得分:1)

你可以:

  • 使用WMI和WMI事件来检测硬件更改。
  • 使用隐藏的WinForms窗口覆盖WinProc方法来获取WM_DEVICECHANGE