Escribo una aplicación en C#, .NET 3.0 en VS2005 con una función de monitorización de inserción/expulsión de varias unidades extraíbles (discos flash USB, CD-ROM, etc.). No quería usar WMI, ya que a veces puede ser ambiguo (por ejemplo, puede generar múltiples eventos de inserción para una sola unidad USB), así que simplemente anulo el WndProc de mi mainform para capturar el mensaje WM_DEVICECHANGE, como se propone here. Ayer me encontré con un problema cuando resultó que tendré que usar WMI de todos modos para recuperar algunos detalles oscuros del disco como un número de serie. Resulta que llamar a rutinas WMI desde dentro del WndProc arroja el DisconnectedContext MDA.DisconnectedContext MDA al llamar a funciones WMI en la aplicación de un único subproceso
Después de excavar, terminé con una solución incómoda para eso. El código es como sigue:
// 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();
que básicamente significa ejecutar el procedimiento relacionados con WMI en un hilo separado - pero entonces, a la espera de que se complete.
Ahora, la pregunta es: ¿por qué lo hace funcionar, y por eso qué tiene que ser así? (o, ¿lo hace?)
No entiendo el hecho de obtener DisconnectedContext MDA o RPC_E_WRONG_THREAD en primer lugar. ¿Cómo funciona ejecutar el procedimiento GetDrives()
desde un controlador de evento de clic de botón difiere de invocarlo desde un WndProc? ¿No ocurren en el mismo hilo principal de mi aplicación? Por cierto, mi aplicación es completamente de un solo hilo, entonces ¿por qué, de repente, un error que se refiere a un "hilo equivocado"? ¿El uso de WMI implica multihilo y un tratamiento especial de las funciones de System.Management?
Mientras tanto encontré otra pregunta relacionada con esa MDA, es here. OK, puedo asumir que llamar a WMI significa crear un hilo separado para el componente COM subyacente, pero todavía no se me ocurre por qué no se necesita magia al llamarlo después de presionar un botón y se necesita hacer magia cuando se llama desde el WndProc.
Estoy realmente confundido acerca de eso y agradecería alguna aclaración al respecto. Sólo hay unas pocas cosas peores que tener una solución y no saber por qué funciona:/
Saludos, Aleksander
¡El mismo problema aquí! Ojalá hubiera una solución. Agregaré una recompensa ... tal vez eso ayude. – Brad