DFL分析(三)消息转发机制

本文探讨了DFL框架中窗口回调函数的实现机制。通过全局窗口列表关联数组保存窗口类,利用消息类处理WM_NCCREATE等消息。对比了不同框架如Stewart's DWindows Framework和DFramework的实现方式。

总想对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结构,利用指令,动态产生汇编代码,替换了窗口回调函数指针,也很精巧。

 


这样,就在回调函数接收到消息后,发给了每个对应的窗口类。每个窗口类根据可以在对应的事件中,进行处理。

解释一下这个代码 #include "first.h" /** * angel process for lighttpd * * the purpose is the run as root all the time and handle: * - restart on crash * - spawn on HUP to allow graceful restart * - ... * * it has to stay safe and small to be trustable */ #ifdef _WIN32 #include <stdio.h> int main (void) { fprintf(stderr, "lighttpd-angel is not implemented on Windows. " "Prefer using Windows services.\n"); return 1; } #else /* ! _WIN32 */ #include <sys/wait.h> #include <stdio.h> #include <errno.h> #include <signal.h> #include <unistd.h> /* _exit() execvp() fork() */ #define BINPATH SBIN_DIR"/lighttpd" static volatile sig_atomic_t restart = 0; static pid_t pid = -1; __attribute_cold__ static void signal_handler (int sig) { if (pid <= 0) return; if (sig == SIGHUP) { /* trigger graceful shutdown of lighttpd, then restart lighttpd */ sig = SIGINT; restart = -1; } /* forward signal to the child */ kill(pid, sig); } __attribute_cold__ static void signal_setup (void) { signal(SIGCHLD, SIG_DFL); signal(SIGALRM, SIG_DFL); signal(SIGPIPE, SIG_IGN); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGUSR1, signal_handler); signal(SIGHUP, signal_handler); } __attribute_cold__ int main (int argc, char **argv) { UNUSED(argc); *(const char **)&argv[0] = BINPATH; #ifdef __COVERITY__ __coverity_tainted_data_sanitize__(argv); #endif signal_setup(); do { if (-1 == pid) { pid = fork(); if (-1 == pid) return -1; if (0 == pid) { /* intentionally pass argv params */ /* coverity[tainted_string : FALSE] */ execvp(argv[0], argv); _exit(1); } } int exitcode = 0; if ((pid_t)-1 == waitpid(pid, &exitcode, 0)) { if (errno == ECHILD) break; /* child exists; should not happen */ continue; } const char *msg = NULL; int code = 0; if (WIFEXITED(exitcode)) { code = WEXITSTATUS(exitcode); msg = "%s.%d: child (pid=%d) exited normally with exitcode: %d\n"; } else if (WIFSIGNALED(exitcode)) { code = WTERMSIG(exitcode); msg = "%s.%d: child (pid=%d) exited unexpectedly with signal %d, " "restarting\n"; restart = -1; } if (msg) fprintf(stderr, msg, __FILE__, __LINE__, pid, code); pid = restart; /* -1 for restart, 0 to exit */ restart = 0; } while (pid != 0); return 0; } #endif /* ! _WIN32 */
09-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值