技术开发 频道

WPF的画图请求是如何生成和派发


【IT168技术文档】

  WPF通过System.Windows.Media.Composition.DUCE相关函数跟worker thread通信,具体来说是通过kernel object来实现的。仔细研究了DUCE内相关函数后,发现这个东西相当有货,从暴露出来的函数名字,就可以猜测到UI thread和render thread的交互模型。应该是UI thread准备好足够的数据后,然后发送请求通知Render thread,然后Render thread拿到对应的请求完成工作。从名字上看,下面这个函数就非常的值得关注:

  System.Windows.Media.Composition.DUCE+Channel.SendCommand

  接下来的任务就是通过调试器来进一步分析UI thread中具体发生了些什么事情。如果能拿到足够多的callstack sample,这对于通过reflector研究WPF实现是很有帮助的。我的下一个目标是,分析WPF的窗口绘画到底是如何进行的。

  观察WPF窗口绘画的简单办法就是写一个死循环,在循环中做一些重画的工作。我这里选择改变窗口背景。我决定用下面的办法来做:
void button2_Click(Object sender, RoutedEventArgs e) { while(true) { this.Background=new SolidBrush(...); //red this.Background=new SolidBrush(...); //black } }
  很可惜,我发现这个方法不能循环改变窗口背景。我决定换一个方法,在timer里面来做这个事情。在WPF的帮助文档中找到DispatchTimer,成功实现了窗口背景的循环重绘。在窗口死循环绘制的时候,用Windbg断下来,检查System.Windows.Media.Composition.DUCE+Channel.SendCommand函数的触发情况:
0:000> !name2ee PresentationCore.dll!System.Windows.Media.Composition.DUCE+Channel.SendCommand Module: 53cb8000 (PresentationCore.dll) Token: 0x060004e2 MethodDesc: 53e2d808 Name: System.Windows.Media.Composition.DUCE+Channel.SendCommand(Byte*, Int32) JITTED Code Address: 538f61c0 0:000> bp 538f61c0 0:000> g Breakpoint 0 hit eax=013c4428 ebx=00000007 ecx=013c4428 edx=0012e888 esi=013c4428 edi=013e6e14 eip=538f61c0 esp=0012e880 ebp=013ff898 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 PresentationCore_ni+0xb61c0: 538f61c0 55 push ebp 0:000> !clrstack OS Thread Id: 0xffc (0) ESP EIP 0012e880 538f61c0 System.Windows.Media.Composition.DUCE+Channel.SendCommand(Byte*, Int32) 0012e888 539169f2 System.Windows.Media.Composition.DUCE+CompositionNode.SetContent(ResourceHandle, ResourceHandle, Channel) 0012e89c 538e4f2e System.Windows.UIElement.RenderContent(System.Windows.Media.RenderContext, Boolean) 0012e8b4 538ea5ed System.Windows.Media.Visual.RenderRecursive(System.Windows.Media.RenderContext) 0012e8f8 538eabcf System.Windows.Media.Visual.UpdateChildren(System.Windows.Media.RenderContext, ResourceHandle) 0012e920 538ea652 System.Windows.Media.Visual.RenderRecursive(System.Windows.Media.RenderContext) 0012e964 538ea3ea System.Windows.Media.Visual.Render(System.Windows.Media.RenderContext, UInt32) 0012e980 53914b9a System.Windows.Media.CompositionTarget.Compile(Channel) 0012e994 539121d5 System.Windows.Media.CompositionTarget.System.Windows.Media.ICompositionTarget.Render(Boolean, Channel) 0012e9bc 539119ee System.Windows.Media.MediaContext.Render(System.Windows.Media.ICompositionTarget) 0012ea80 53910f87 System.Windows.Media.MediaContext.RenderMessageHandlerCore(System.Object) 0012eac8 53910ea0 System.Windows.Media.MediaContext.RenderMessageHandler(System.Object) 0012eae0 5686ec0a System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Boolean) 0012eafc 5686eb3f System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Boolean, System.Delegate) 0012eb44 56874138 System.Windows.Threading.DispatcherOperation.InvokeImpl() 0012eb80 56874020 System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(System.Object) 0012eb88 79360acf System.Threading.ExecutionContext.runTryCode(System.Object) 0012efb0 79e7be1b [HelperMethodFrame_PROTECTOBJ: 0012efb0] System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) 0012f018 79360a1b System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 0012f030 7936090e System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 0012f048 56873fa4 System.Windows.Threading.DispatcherOperation.Invoke() 0012f05c 56873f02 System.Windows.Threading.Dispatcher.ProcessQueue() 0012f098 56873ce6 System.Windows.Threading.Dispatcher.WndProcHook(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) 0012f0f0 5686eea3 MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) 0012f12c 5686edbc MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object) 0012f150 5686ec0a System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Boolean) 0012f16c 5686eb3f System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Boolean, System.Delegate) 0012f1b4 5686e53f System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Boolean) 0012f204 5686e3d5 System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority, System.Delegate, System.Object) 0012f228 5686dcba MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr) 0012f3a8 003921bc [NDirectMethodFrameStandalone: 0012f3a8] MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef) 0012f3b8 56873370 System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) 0012f408 56873213 System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame) 0012f424 5687316d System.Windows.Threading.Dispatcher.Run() 0012f430 54f1db7f System.Windows.Application.RunInternal(System.Windows.Window) 0012f460 54f1d9a9 System.Windows.Application.Run(System.Windows.Window) 0012f470 54f1d5d6 System.Windows.Application.Run() 0012f47c 00df00ad WPFThreadingModel.App.Main() 0012f69c 79e7be1b [GCFrame: 0012f69c]
0
相关文章