一,作用
提供线程队列服务,通过windows message 这个基本原理逻辑代码。
二,代码
异步调用
dispacher 把我们行为封装成为DispatcherOperation,然后投递队列,同时投递事件给绑定的线程对应的 message only 窗口,窗口收到消息就运行我的行为。
写c++开发时候,为了拥有这样功能,我们都要自己写窗口,封装异步行为,到了WPF 这个已经是自带功能。
private void InvokeAsyncImpl(DispatcherOperation operation, CancellationToken cancellationToken)
{
DispatcherHooks hooks = null;
bool succeeded = false;
// Could be a non-dispatcher thread, lock to read
lock(_instanceLock)
{
if (!cancellationToken.IsCancellationRequested &&
!_hasShutdownFinished &&
!Environment.HasShutdownStarted)
{
// Add the operation to the work queue
//当前行为添加到队列里面去
operation._item = _queue.Enqueue(operation.Priority, operation);
// Make sure we will wake up to process this operation.
//投递消息给创建window,这样子处理消息
succeeded = RequestProcessing();
if (succeeded)
{
// Grab the hooks to use inside the lock; but we will
// call them below, outside of the lock.
hooks = _hooks;
}
else
{
// Dequeue the item since we failed to request
// processing for it. Note we will mark it aborted
// below.
_queue.RemoveItem(operation._item);
}
}
}
if (succeeded == true)
{
// We have enqueued the operation. Register a callback
// with the cancellation token to abort the operation
// when cancellation is requested.
if(cancellationToken.CanBeCanceled)
{
CancellationTokenRegistration cancellationRegistration = cancellationToken.Register(s => ((DispatcherOperation)s).Abort(), operation);
// Revoke the cancellation when the operation is done.
operation.Aborted += (s,e) => cancellationRegistration.Dispose();
operation.Completed += (s,e) => cancellationRegistration.Dispose();
}
if(hooks != null)
{
hooks.RaiseOperationPosted(this, operation);
}
if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordDispatcher | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
{
EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientUIContextPost, EventTrace.Keyword.KeywordDispatcher | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, operation.Priority, operation.Name, operation.Id);
}
}
else
{
// We failed to enqueue the operation, and the caller that
// created the operation does not expose it before we return,
// so it is safe to modify the operation outside of the lock.
// Just mark the operation as aborted, which we can safely
// return to the user.
operation._status = DispatcherOperationStatus.Aborted;
operation._taskSource.SetCanceled();
}
}
创建dispacher
- 添加全局list dispacher【全局管理】
- 创建MessageOnlyHwndWrappe 窗口,这个是核心的功能。
- 添加 窗口消息处理函数 WndProcHook
[SecurityCritical, SecurityTreatAsSafe]
private Dispatcher()
{
_queue = new PriorityQueue<DispatcherOperation>();
_tlsDispatcher = this; // use TLS for ownership only
_dispatcherThread = Thread.CurrentThread;
// Add ourselves to the map of dispatchers to threads.
lock(_globalLock)
{
//全局list 增加 当前的list
_dispatchers.Add(new WeakReference(this));
}
_unhandledExceptionEventArgs = new DispatcherUnhandledExceptionEventArgs(this);
_exceptionFilterEventArgs = new DispatcherUnhandledExceptionFilterEventArgs(this);
_defaultDispatcherSynchronizationContext = new DispatcherSynchronizationContext(this);
// Create the message-only window we use to receive messages
// that tell us to process the queue.
MessageOnlyHwndWrapper window = new MessageOnlyHwndWrapper();
_window = new SecurityCriticalData<MessageOnlyHwndWrapper>( window );
_hook = new HwndWrapperHook(WndProcHook);
_window.Value.AddHook(_hook);
// DDVSO:447590
// Verify that the accessibility switches are set prior to any major UI code running.
AccessibilitySwitches.VerifySwitches(this);
}
WndProcHook
处理窗口消息,用来处理 我们投递过来的异步操作
private IntPtr WndProcHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
WindowMessage message = (WindowMessage)msg;
if(_disableProcessingCount > 0)
{
throw new InvalidOperationException(SR.Get(SRID.DispatcherProcessingDisabledButStillPumping));
}
if(message == WindowMessage.WM_DESTROY)
{
if(!_hasShutdownStarted && !_hasShutdownFinished) // Dispatcher thread - no lock needed for read
{
// Aack! We are being torn down rudely! Try to
// shut the dispatcher down as nicely as we can.
ShutdownImpl();
}
}
else if(message == _msgProcessQueue)
{
//如果消息,异步投递消息
//这个就是我们用dispacher beginInvoke的
// 内部调用 RequestProcessing(); 投递回调消息过来
ProcessQueue();
}
else if(message == WindowMessage.WM_TIMER && (int) wParam == TIMERID_BACKGROUND)
{
// This timer is just used to process background operations.
// Stop the timer so that it doesn't fire again.
SafeNativeMethods.KillTimer(new HandleRef(this, hwnd), TIMERID_BACKGROUND);
ProcessQueue();
}
else if(message == WindowMessage.WM_TIMER && (int) wParam == TIMERID_TIMERS)
{
// We want 1-shot only timers. So stop the timer
// that just fired.
KillWin32Timer();
PromoteTimers(Environment.TickCount);
}
// We are about to return to the OS. If there is nothing left
// to do in the queue, then we will effectively go to sleep.
// This is the condition that means Idle.
DispatcherHooks hooks = null;
bool idle = false;
lock(_instanceLock)
{
idle = (_postedProcessingType < PROCESS_BACKGROUND);
if (idle)
{
hooks = _hooks;
}
}
if (idle)
{
if(hooks != null)
{
hooks.RaiseDispatcherInactive(this);
}
ComponentDispatcher.RaiseIdle();
}
return IntPtr.Zero ;
}
获取当前dispatcher
- 通过FromThread 函数获取 当前线程的dispacher
- 如果当前线程不存在dispacher,那么直接创建。
public static Dispatcher CurrentDispatcher
{
get
{
// Find the dispatcher for this thread.
Dispatcher currentDispatcher = FromThread(Thread.CurrentThread);;
// Auto-create the dispatcher if there is no dispatcher for
// this thread (if we are allowed to).
if(currentDispatcher == null)
{
currentDispatcher = new Dispatcher();
}
return currentDispatcher;
}
}
我们可以new Thread ,然后执行获当前dispacher。
消息循环
//<SecurityNote>
// Critical - as this calls critical methods (GetMessage, TranslateMessage, DispatchMessage).
// TreatAsSafe - as the critical method is not leaked out, and not controlled by external inputs.
//</SecurityNote>
[SecurityCritical, SecurityTreatAsSafe ]
private void PushFrameImpl(DispatcherFrame frame)
{
SynchronizationContext oldSyncContext = null;
SynchronizationContext newSyncContext = null;
MSG msg = new MSG();
_frameDepth++;
try
{
// Change the CLR SynchronizationContext to be compatable with our Dispatcher.
oldSyncContext = SynchronizationContext.Current;
newSyncContext = new DispatcherSynchronizationContext(this);
SynchronizationContext.SetSynchronizationContext(newSyncContext);
try
{
while(frame.Continue)
{
if (!GetMessage(ref msg, IntPtr.Zero, 0, 0))
break;
TranslateAndDispatchMessage(ref msg);
}
// If this was the last frame to exit after a quit, we
// can now dispose the dispatcher.
if(_frameDepth == 1)
{
if(_hasShutdownStarted)
{
ShutdownImpl();
}
}
}
finally
{
// Restore the old SynchronizationContext.
SynchronizationContext.SetSynchronizationContext(oldSyncContext);
}
}
finally
{
_frameDepth--;
if(_frameDepth == 0)
{
// We have exited all frames.
_exitAllFrames = false;
}
}
}
如果普通的windwos 窗口程序,一般只有一个消息循环,消息循环每个线程必须要有一个。如果你创建windows不在UI线程,那么必须自己循环,不然程序跑不起来。
Appliaction 继承了 DispatcherObject,那么默认创建一个dispacker的对象。
/// <summary>
/// Instantiate this object associated with the current Dispatcher.
/// </summary>
protected DispatcherObject()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
可以退出,如果wpf起码有2个窗口,dispacher创建窗口。

wpf 程序会调用dispacher Run
我通过自己写c++ 工具搜索消息窗口(消息窗口不能被枚举函数枚举,所以你用spy++是无法查找到这个窗口,必须通过下面FindWindowEx函数才可以)
void find_hwnd_message(HWND hw){
HWND child_hwnd = FindWindowEx(HWND_MESSAGE, hw, NULL, NULL);
if(child_hwnd == NULL){
return;
}
wchar_t class_name[256] = {0};
GetClassName(hw, class_name, 255);
wprintf_s(L"class_name: %s\n", class_name );
find_hwnd_message(child_hwnd);
}
然后再main函数调用 find_hwnd_message (null); 这样子可以查询所有的消息窗口,你也可以填写class name 和 windows name 做过滤。
三、总结
application 启动时候就默认创建 dispacher,通过Dispacher 获取当前的,当前不存在就默认创建逻辑,然后启动主窗口,然后调用当前dispacher中Run ,用来消息循环,从而整个window 应用程序核心逻辑走完了。dispacher会绑定线程,会创建一个消息窗口。通过原理,我们可以推出来,dispacher是不能在很短时间做大量异步行为(如果消息还消耗时间的话),因为dispacher 消息处理不过来,阻塞界面。