2011-08-04 10 views
7

¿Qué hace exactamente Control.Invoke (Delegate) para que el delegado se ejecute en el hilo de la GUI? Además, entiendo que la invocación se bloqueará hasta que se complete la función invocada. ¿Cómo logra esto?Curioso acerca de la implementación de Control.Invoke()

Me gustaría tener algunos detalles valiosos. Espero aprender algo interesante.

+0

Compruebe [esto] [1] hacia fuera. [1]: http://stackoverflow.com/questions/4514273/does-control-invoke-pump-messages – n8wrl

Respuesta

4

Editar: El control implementa la interfaz ISynchronizeInvoke, Puede hacer el mismo efecto utilizando el SynchronizationContext y llame al Post cuando llame al Invoke. algo así como:

public object Invoke(Delegate method, object[] args) 
{ 
    if (method == null) 
    { 
     throw new ArgumentNullException("method"); 
    } 

    object objectToGet = null; 

    SendOrPostCallback invoker = new SendOrPostCallback(
    delegate(object data) 
    { 
     objectToGet = method.DynamicInvoke(args); 
    }); 

    _currentContext.Send(new SendOrPostCallback(invoker), method.Target); 

    return objectToGet; 
} 

nuevas investigaciones utilizando Reflector muestra que el Invoke utiliza alguna API nativa insta a lograr que:

private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous) 
{ 
    int num; 
    if (!this.IsHandleCreated) 
    { 
     throw new InvalidOperationException(SR.GetString("ErrorNoMarshalingThread")); 
    } 
    if (((ActiveXImpl) this.Properties.GetObject(PropActiveXImpl)) != null) 
    { 
     IntSecurity.UnmanagedCode.Demand(); 
    } 
    bool flag = false; 
    if ((SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, this.Handle), out num) == SafeNativeMethods.GetCurrentThreadId()) && synchronous) 
    { 
     flag = true; 
    } 
    ExecutionContext executionContext = null; 
    if (!flag) 
    { 
     executionContext = ExecutionContext.Capture(); 
    } 
    ThreadMethodEntry entry = new ThreadMethodEntry(caller, this, method, args, synchronous, executionContext); 
    lock (this) 
    { 
     if (this.threadCallbackList == null) 
     { 
      this.threadCallbackList = new Queue(); 
     } 
    } 
    lock (this.threadCallbackList) 
    { 
     if (threadCallbackMessage == 0) 
     { 
      threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage"); 
     } 
     this.threadCallbackList.Enqueue(entry); 
    } 
    if (flag) 
    { 
     this.InvokeMarshaledCallbacks(); 
    } 
    else 
    { 
     UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero); 
    } 
    if (!synchronous) 
    { 
     return entry; 
    } 
    if (!entry.IsCompleted) 
    { 
     this.WaitForWaitHandle(entry.AsyncWaitHandle); 
    } 
    if (entry.exception != null) 
    { 
     throw entry.exception; 
    } 
    return entry.retVal; 
} 
1

Si yo quiero saber internos, por lo general el fuego de ILSpy y observe el fuentes decompiladas del BCL. Alternativamente, puede descargar las fuentes Mono o Rotor.

+2

O utilizar el reflector;) – Abel

+0

¿No te digo la mala palabra "R"! ;-) –

+0

Si la licencia de Reflector cambió, comencé a usar el descompilador de Telerik y me gusta: http://www.keepdecompilingfree.com – Jamey