经过一些挖掘,我最终采用了一个尴尬的解决方法。代码如下:
// 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调用它时需要魔法。
我真的对此感到困惑,并希望能够澄清这个问题。只有几件比拥有解决方案但不知道为什么它有效的事情更糟糕:/
干杯, Aleksander