2012-08-31 9 views
6

Estoy usando WMI para consultar dispositivos. Necesito actualizar la IU cuando se inserta o quita un dispositivo nuevo (para mantener la lista de dispositivos actualizada).La aplicación llamó a una interfaz que se organizó para un hilo diferente

private void LoadDevices() 
{ 
    using (ManagementClass devices = new ManagementClass("Win32_Diskdrive")) 
    { 
     foreach (ManagementObject mgmtObject in devices.GetInstances()) 
     { 
      foreach (ManagementObject partitionObject in mgmtObject.GetRelated("Win32_DiskPartition")) 
      { 
       foreach (ManagementBaseObject diskObject in partitionObject.GetRelated("Win32_LogicalDisk")) 
       { 
        trvDevices.Nodes.Add(...); 
       } 
      } 
     } 
    } 
} 

protected override void WndProc(ref Message m) 
{ 
    const int WM_DEVICECHANGE = 0x0219; 
    const int DBT_DEVICEARRIVAL = 0x8000; 
    const int DBT_DEVICEREMOVECOMPLETE = 0x8004; 
    switch (m.Msg) 
    { 
     // Handle device change events sent to the window 
     case WM_DEVICECHANGE: 
      // Check whether this is device insertion or removal event 
      if (
       (int)m.WParam == DBT_DEVICEARRIVAL || 
       (int)m.WParam == DBT_DEVICEREMOVECOMPLETE) 
     { 
      LoadDevices(); 
     } 

     break; 
    } 

    // Call base window message handler 
    base.WndProc(ref m); 
} 

Este código genera una excepción con el siguiente texto

The application called an interface that was marshalled for a different thread.

puse

MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString()); 

en el comienzo del método LoadDevices y veo que siempre es llamado desde el mismo hilo (1). ¿Podría explicar qué está pasando aquí y cómo deshacerse de este error?

Respuesta

2

Finalmente lo resolví usando un hilo nuevo. Divido este método, así que ahora tengo los métodos GetDiskDevices() y LoadDevices(List<Device>) y tengo el método InvokeLoadDevices().

private void InvokeLoadDevices() 
{ 
    // Get list of physical and logical devices 
    List<PhysicalDevice> devices = GetDiskDevices(); 

    // Check if calling this method is not thread safe and calling Invoke is required 
    if (trvDevices.InvokeRequired) 
    { 
     trvDevices.Invoke((MethodInvoker)(() => LoadDevices(devices))); 
    } 
    else 
    { 
     LoadDevices(devices); 
    } 
} 

Cuando llego a cualquiera de los mensajes DBT_DEVICEARRIVAL o DBT_DEVICEREMOVECOMPLETE me llaman

ThreadPool.QueueUserWorkItem(s => InvokeLoadDevices()); 

Gracias.

0

Para uwp en w10 puede usar:

public async SomeMethod() 
{ 
    await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.High,() => 
     { 
      // Your code here... 
     }); 
} 
Cuestiones relacionadas