我正在爲WPF編寫一個目錄選擇器控件,並且我希望在目錄樹被掛載或卸載時,或者準備就緒或未準備好時(例如,用戶插入或刪除CD),從驅動器中添加/ 。我正在尋找類似於WM_DEVICECHANGE
的系統事件。驅動器掛載或更改狀態時檢測到(WPF的WM_DEVICECHANGE)?
康斯坦丁
我正在爲WPF編寫一個目錄選擇器控件,並且我希望在目錄樹被掛載或卸載時,或者準備就緒或未準備好時(例如,用戶插入或刪除CD),從驅動器中添加/ 。我正在尋找類似於WM_DEVICECHANGE
的系統事件。驅動器掛載或更改狀態時檢測到(WPF的WM_DEVICECHANGE)?
康斯坦丁
我使用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
您可以:
WinProc
方法來獲取WM_DEVICECHANGE
。即使您使用的是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);
}
}
的得到它下面的代碼爲我工作。它訂閱了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);
}
}
}
}
感謝。我懷疑這是不可移植的,它不會在其他操作系統上工作。你會解釋在OnSourceInitialized方法中創建SystemEventIntercept對象的目的是什麼,而不是在任何地方使用它? – akonsu 2010-09-22 18:53:09
@akonsu:是的,這個解決方案不是可移植的,但我不認爲WPF也是。當你的WPF窗口的底層Win32句柄被創建時,調用「OnSourceInitialized」,所以它是一個方便的地方。 SystemEventIntercept實際上是在做一些事情,當它被創建時,它立即開始收聽消息。當你攔截「WM_DEVICECHANGE」時,你可以在'// do something'評論中做任何你需要的。我的代碼只是一個例子,您可能需要對其進行修改以適應您的需求。 – 2010-09-22 19:14:12
+1:正是我需要檢測專用USB設備,因爲接受答案只會檢測存儲設備。起初,這個解決方案在我使'SystemEventIntercept截獲'屬性而不是局部變量之前不起作用,然後它運行良好。作爲一個局部變量(這從來沒有使用過),它一定是幾乎立即收集垃圾。 – 2012-12-27 08:56:13