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.IC