VS2005 の C#、.NET 3.0 で、さまざまなリムーバブル ドライブ (USB フラッシュ ディスク、CD-ROM など) の挿入/排出を監視する機能を備えたアプリを作成します。WMI はあいまいな場合があるため (たとえば、単一の USB ドライブに対して複数の挿入イベントが発生する可能性があるため)、WMI を使用したくなかったため、ここで提案されているように、メインフォームの 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 コンポーネント用に別のスレッドを作成することを意味すると理解できます。 WndProc から。
私はそれについて本当に混乱しており、その問題についていくつかの説明をいただければ幸いです。解決策を持っていて、それが機能する理由がわからないことよりも悪いことはいくつかあります:/
乾杯、アレクサンダー