总想对DFL的机制进行深入的分析,但却沉迷应用,并且发现自己了解的还很浅显,不足为分析。
在看了几个GUI的回调函数实现后,终于发现了端倪。于是,有了本篇。
在我们使用面向对象机制来开发Windows程序中,我们面临的问题就是如何把静态的windows窗口回调函数调用绑定到每个(窗口)类上。我们知道,回调函数是一个固定的函数原型,并且在注册窗口类时要传递的函数指针。而我们的窗口类呢?类是无法在包含这个函数的。除非这个函数是静态函数。而静态函数又失去了我们的继承多态优点。
可以定义一个全局的窗口列表,存储每个窗口类的指针和HWND,然后再定位对象内部的消息处理函数。这是一个解决的办法。对了,DFL就是这么处理的!
让我们看看DFL的窗口回调函数:
extern(Windows) LRESULT dflWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
它利用了Application的静态变量Control[HWND] controls关联数组,保存了所有的control(窗口)类。
针对每个消息:创建一个消息类Message dm = Message(hwnd, msg, wparam, lparam),这里没有用到hwnd,
1.在创建control时,接收了WM_NCCREATE消息:保存控件(窗口)到数组。
Application.controls[hwnd] = ctrl;
ctrl.hwnd = hwnd;
2.对其他消息:
使用 ctrl = Application.lookupHwnd(hwnd); 根据hwnd查找对应的控件(窗口)指针。
将创建的消息类发送给ctrl:调用ctrl.mustWndProc(),ctrl.preProcessMessage,ctrl._wndProc
Stewart's D Windows Framework使用了和DFL一样的方法。
而Selcuk IYIKALENDER的D Framework使用的是另外一个办法:
他使用了一个用户数据,在创建窗口时,使用SetWindowLongW将窗口指针保存在GWL_USERDATA中。GWL_USERDATA是
每个窗口的用户数据,这样就可以在消息到来的时候,通过w = cast(Window) cast(void*) GetWindowLongW( hWnd, GWL_USERDATA ),在窗口hwnd句柄 的用户数据中取得窗口的指针。将消息发送给具体的窗口了。
前几天看WTL,发现ATL中有个Thunk结构,利用指令,动态产生汇编代码,替换了窗口回调函数指针,也很精巧。
这样,就在回调函数接收到消息后,发给了每个对应的窗口类。每个窗口类根据可以在对应的事件中,进行处理。