Ich schreibe eine App in C#, .NET 3.0 in VS2005 mit einer Funktion zur Überwachung der Einfügung/Auswurf von verschiedenen Wechsellaufwerken (USB-Flash-Laufwerke, CD-ROMs etc.). Ich wollte WMI nicht verwenden, da es manchmal mehrdeutig sein kann (z. B. kann es mehrere Einfügungsereignisse für ein einzelnes USB-Laufwerk erzeugen), so überschreibe ich einfach den WndProc meines Hauptformulars, um die WM_DEVICECHANGE-Nachricht abzufangen, wie vorgeschlagen here. Gestern habe ich auf ein Problem gestoßen, als sich herausstellte, dass ich sowieso WMI verwenden muss, um einige obskure Disk-Details wie eine Seriennummer zu erhalten. Es stellt sich heraus, dass das Aufrufen von WMI-Routinen aus dem WndProc den DisconnectedContext-MDA auslöst.DisconnectedContext MDA beim Aufruf von WMI-Funktionen in Single-Thread-Anwendung
Nach etwas graben endete ich mit einem peinlichen Workaround dafür. Der Code lautet wie folgt:
// 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();
was im Grunde bedeutet das WMI-bezogenen Verfahren auf einem separaten Thread ausgeführt wird - aber dann, warten auf sie vervollständigen zu.
Nun, die Frage ist: warum funktioniert es, und warum muss es so sein? (oder, oder?)
Ich verstehe nicht die Tatsache, den DisconnectedContext MDA oder RPC_E_WRONG_THREAD an erster Stelle zu bekommen. Wie unterscheidet sich das Ausführen der GetDrives()
-Prozedur von einem Ereignishandler für das Klicken auf Schaltflächen nicht davon, dass es von einem WndProc aufgerufen wird? Passieren sie nicht im selben Hauptthread meiner App? Übrigens, meine App ist komplett single-threaded, warum also plötzlich ein Fehler, der sich auf einen "falschen Thread" bezieht? Bedeutet der Einsatz von WMI Multithreading und spezielle Behandlung von Funktionen von System.Management?
In der Zwischenzeit habe ich eine andere Frage zu diesem MDA gefunden, es ist here. OK, ich kann es so nehmen, dass das Aufrufen von WMI bedeutet, einen separaten Thread für die zugrunde liegende COM-Komponente zu erstellen - aber mir fällt immer noch nicht ein, warum no-magic beim Aufruf nach dem Drücken einer Taste benötigt wird und do-magic beim Aufruf benötigt wird es aus dem WndProc.
Ich bin wirklich verwirrt darüber und würde eine Klärung in dieser Angelegenheit schätzen. Es gibt nur wenige Dinge schlimmer als eine Lösung mit und ohne zu wissen, warum es funktioniert:/
Cheers, Aleksander
Gleiche Probleme hier! Ich wünschte, es gäbe eine Lösung. Ich werde ein Kopfgeld hinzufügen ... vielleicht wird das helfen. – Brad