Scrivo un'app in C#, .NET 3.0 in VS2005 con una funzionalità di monitoraggio dell'inserimento/espulsione di varie unità rimovibili (dischi flash USB, CD-ROM, ecc.). Non volevo usare WMI, dal momento che può essere a volte ambiguo (ad esempio può generare più eventi di inserimento per una singola unità USB), quindi semplicemente sovrascrivo il WndProc della mia mainform per catturare il messaggio WM_DEVICECHANGE, come proposto here. Ieri mi sono imbattuto in un problema quando è risultato che dovrò comunque utilizzare WMI per recuperare alcuni dettagli del disco oscuri come un numero seriale. Si scopre che la chiamata alle routine WMI dall'interno del WndProc genera l'MDA DisconnectedContext.DisconnectedContext MDA quando si chiamano le funzioni WMI nell'applicazione a thread singolo
Dopo alcuni lavori di scavo, ho concluso con una soluzione scomoda per questo. Il codice è il seguente:
// 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();
che sostanzialmente significa che esegue la procedura WMI correlata a un thread separato - ma poi, in attesa che sia completato.
Ora, la domanda è: perché funziona, e perché ha a essere in questo modo? (o, vero?)
Non capisco il fatto di ottenere il DisconnectedContext MDA o RPC_E_WRONG_THREAD in primo luogo. In che modo la procedura GetDrives()
da un gestore eventi di clic sui pulsanti differisce dal chiamarla da un WndProc? Non si verificano sullo stesso thread principale della mia app? A proposito, la mia app è completamente single-threaded, quindi perché all'improvviso un errore si riferisce ad un "thread sbagliato"? L'utilizzo di WMI implica il multithreading e il trattamento speciale delle funzioni da System.Management?
Nel frattempo ho trovato un'altra domanda relativa a tale MDA, è here. OK, posso dire che chiamare WMI significa creare un thread separato per il componente COM sottostante - ma ancora non mi viene in mente il motivo per cui la non magia è necessaria quando la si chiama dopo che un pulsante è stato premuto e do-magic è necessario quando si chiama dal WndProc.
Sono davvero confuso e apprezzerei qualche chiarimento in merito. Ci sono solo poche cose peggiori che avere una soluzione e non sapere perché funziona:/
Cheers, Aleksander
Lo stesso problema qui! Vorrei che ci fosse una soluzione. Aggiungerò una taglia ... forse sarà d'aiuto. – Brad