Любопытно о реализации Control.Invoke () - PullRequest
7 голосов
/ 05 августа 2011

Что именно делает Control.Invoke (Delegate) для запуска делегата в потоке GUI? Кроме того, это мое понимание, что вызов будет блокироваться, пока не будет выполнена вызванная функция. Как это достигается?

Я хотел бы получить несколько хороших подробностей. Я надеюсь узнать что-то интересное.

Ответы [ 2 ]

4 голосов
/ 05 августа 2011

Edit: элемент управления реализует интерфейс ISynchronizeInvoke. Вы можете сделать тот же эффект, используя SynchronizationContext и вызывая Post при вызове Invoke.что-то вроде:

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

Дальнейшие исследования с использованием Reflector показывают, что Invoke использует некоторые собственные вызовы API для достижения этой цели:

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 голос
/ 05 августа 2011

Если я хочу узнать внутреннее устройство, я обычно запускаю ILSpy и смотрю на декомпилированные источники BCL.Кроме того, вы можете загрузить источники Mono или Rotor .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...