2010-09-22 63 views

回答

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

1

您可以:

  • 使用WMI和WMI事件,以检测硬件改动。
  • 使用隐藏的WinForms窗口,并覆盖WinProc方法来获取WM_DEVICECHANGE
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); 
    } 
} 
+0

感谢。我怀疑这是不可移植的,它不会在其他操作系统上工作。你会解释在OnSourceInitialized方法中创建SystemEventIntercept对象的目的是什么,而不是在任何地方使用它? – akonsu 2010-09-22 18:53:09

+1

@akonsu:是的,这个解决方案不是可移植的,但我不认为WPF也是。当你的WPF窗口的底层Win32句柄被创建时,调用“OnSourceInitialized”,所以它是一个方便的地方。 SystemEventIntercept实际上是在做一些事情,当它被创建时,它立即开始收听消息。当你拦截“WM_DEVICECHANGE”时,你可以在'// do something'评论中做任何你需要的。我的代码只是一个例子,您可能需要对其进行修改以适应您的需求。 – 2010-09-22 19:14:12

+0

+1:正是我需要检测专用USB设备,因为接受答案只会检测存储设备。起初,这个解决方案在我使'SystemEventIntercept截获'属性而不是局部变量之前不起作用,然后它运行良好。作为一个局部变量(这从来没有使用过),它一定是几乎立即收集垃圾。 – 2012-12-27 08:56:13

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