我在 VS2005 中用 C#、.NET 3.0 编写了一个应用程序,其功能是监视各种可移动驱动器(USB 闪存盘、CD-ROM 等)的插入/弹出。我不想使用 WMI,因为它有时会模棱两可(例如,它可以为单个 USB 驱动器生成多个插入事件),所以我只需覆盖我的主窗体的 WndProc 以捕获 WM_DEVICECHANGE 消息,如此处建议的那样。昨天我遇到了一个问题,事实证明我无论如何都必须使用 WMI 来检索一些模糊的磁盘详细信息,例如序列号。事实证明,从 WndProc 内部调用 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 相关的问题,它就在这里。好的,我可以认为调用 WMI 意味着为底层 COM 组件创建一个单独的线程 - 但我仍然没有想到为什么在按下按钮后调用它时需要 no-magic 而调用时需要 do-magic它来自 WndProc。
我对此感到非常困惑,并希望对此事做出澄清。只有一些比有解决方案但不知道它为什么起作用更糟糕的事情:/
干杯,亚历山大