我在VS2005的C#,.NET 3.0中編寫了一個應用程序,具有監視插入/彈出各種可移動驅動器(USB閃存盤,CD-ROM等)的功能。我不想使用WMI,因爲它可能有時是不明確的(例如,它可以爲單個USB驅動器產生多個插入事件),所以我簡單地覆蓋了我的mainform的WndProc以捕獲WM_DEVICECHANGE消息,如提議here。昨天我遇到了一個問題,事實證明,我將不得不使用WMI來檢索一些不明確的磁盤細節,如序列號。事實證明,從WndProc內部調用WMI例程會拋出DisconnectedContext MDA。在單線程應用程序中調用WMI函數時DisconnectedContext MDA
經過一番挖掘,我終於解決了一個尷尬的解決方法。代碼如下:
// the function for calling WMI
private void GetDrives()
{
ManagementClass diskDriveClass = new ManagementClass("Win32_DiskDrive");
// THIS is the line I get DisconnectedContext MDA on when it happens:
ManagementObjectCollection diskDriveList = diskDriveClass.GetInstances();
foreach (ManagementObject dsk in diskDriveList)
{
// ...
}
}
private void button1_Click(object sender, EventArgs e)
{
// here it works perfectly fine
GetDrives();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DEVICECHANGE)
{
// here it throws DisconnectedContext MDA
// (or RPC_E_WRONG_THREAD if MDA disabled)
// GetDrives();
// so the workaround:
DelegateGetDrives gdi = new DelegateGetDrives(GetDrives);
IAsyncResult result = gdi.BeginInvoke(null, "");
gdi.EndInvoke(result);
}
}
// for the workaround only
public delegate void DelegateGetDrives();
這基本上意味着在一個單獨的線程上運行WMI相關的過程 - 但隨後,等待它完成。
現在的問題是:爲什麼它的工作原理,並爲什麼難道一定要這樣? (或者,是嗎?)
我不明白在首先獲取DisconnectedContext MDA或RPC_E_WRONG_THREAD的事實。如何從按鈕單擊事件處理程序運行GetDrives()
過程與從WndProc中調用它不同?難道它們不是發生在我的應用程序的同一主線程上嗎?順便說一下,我的應用程序完全是單線程的,那麼爲什麼突然間一個錯誤指的是一些'錯誤的線程'? WMI的使用是否意味着多線程和System.Management中對函數的特殊處理?
與此同時,我發現另一個與MDA有關的問題,它是here。好吧,我可以認爲調用WMI意味着爲底層COM組件創建一個單獨的線程 - 但它仍然不會出現在爲什麼在按下按鈕後調用它時需要無魔法,並且在調用時需要執行魔法它來自WndProc。
我對此非常困惑,並希望對此事進行一些澄清。只有幾個糟糕的事情比有一個解決方案,不知道爲什麼它的工作原理:/
乾杯, 亞歷山大
同樣的麻煩在這裏!我希望有一個解決方案。我會添加一個賞金......也許這會有所幫助。 – Brad 2011-04-13 23:20:00