Curious about the implementation of Control.Invoke()

蓝咒 提交于 2019-12-30 17:59:53

问题


What exactly does Control.Invoke(Delegate) do to get the delegate to run on the GUI thread? Furthermore, Its my understanding that invoke will block until the invoked function its done. How does it achieve this?

I would like some good gritty details. I'm hoping to learn something interesting.


回答1:


Edit: The control implements ISynchronizeInvoke interface, You can make the same effect using the SynchronizationContext and call Post when you call Invoke. something like:

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;
}

Further investigation using Reflector shows that the Invoke uses some native API calls to achieve that:

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;
}



回答2:


If I want to know internals, I usually fire up ILSpy and look at the decompiled sources of the BCL. Alternatively, you could download the Mono or the Rotor sources.



来源:https://stackoverflow.com/questions/6948643/curious-about-the-implementation-of-control-invoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!