![]() |
系统理解Win32 API和MFC(by 温昱 xinxiu123(AT)sina(DOT)com) Win32 API是微软的操作系统Windows提供给开发人员的编程接口,它决定了我们开发的Windows应用程序的能力。MFC是微软为开发人员提供的类库,在某种意义上是对Win32 API的封装。本文试图从全局角度对Win32 API和MFC进行理解──给出二者的概念模型。 本文使用UML描述概念模型。Win32 API本不是面向对象的,我用面向对象的观点去理解它,无非是想表达其全局。 本文参考了MSDN、相关书籍和网上的一些资料,在此一并感谢。 ![]() Win32 API的object有3种:user obj,gdi obj,kernel obj。但是,如果一点不考虑OS本身的支持,就会在有些问题上疑惑,因此,我这里把“operation system负责将中断封装成message”加上。 1、user obj、gdi obj、kernel obj、system 4者的关系 由于是kernel obj部分负责将另外3者联系起来,因此我们在下图中直接深入到kernel obj部分内部。 ![]() 从图中看到,在内存中运行的,除了“负责将中断封装成message”的system支持部分,还有另外3类object:kernel obj、user obj和gdi obj,每个obj都有一个句柄handle与之对应。其中,gdi obj建立了待开发的Windows 应用和外部输出设备的联系,kernel obj中的file建立了内存和永久存储设备的联系。具体说,内存中的file从可以从硬盘上来,如果这个file是可执行文件,它将生成module,module运行起来就是process,process可以包含多条thread,而thread的运行映象最终还是来自于file。thread是kernel obj中最重要的一个,因为消息队列就是thread拥有的,只有thread才能够接受message。对gdi obj、urser obj和file的操作,也是发生在thread中的。所以书都讲,process至少拥有一个thread。 2、展开“system负责将中断封装成message”部分 下面展开“system负责将中断封装成message”部分,尽早解除对“message到底是怎么形成的”的困惑。 ![]() 3、展开“gdi obj”部分 开发人员可以通过gdi obj将app的信息反馈给User。 4.1 第1次迭代 window在Windows应用开发中占有重要地位。 ![]() ![]() 从图中看到,CreateWindow()负责为window建立与窗口类的联系。每个window都有一个窗口类与之对应,而一个窗口类可以对应多个window。窗口类中记录了窗口函数和菜单等资源信息,而由file生成的module正是窗口函数和资源的老家。 4.2 第2次迭代 考察消息种类。
还是不好,因为当我们调用CreateWindow() API函数时,明明感觉CHILD、OVERLAPPED、POPUP是“window
style”。我再画一张图。 总结user obj: 从图中看到,CreateDialog()和CreateWindow()最大的区别就是,它有对话框模板支持方便地定制dialog界面。注意,Dialog是特殊的window,窗口类它一定也是有的。 前面我们研究了WIN32 API的“领域模型”,对它有较全面的认识。下面,对MFC概念模型的研究,我们把重点放在对app framework的研究上。 也许有些程序员只知道hook机制可以编写很“牛”的应用,孰不知MFC本身也是依靠hook机制的。 2.1 回忆API中Message响应函数的安装 API中Message响应函数的安装,是由CreateWindow()实现的,它将window与一个windowClass联系起来,而后者中记录了Message响应函数的指针。 int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow) { WNDCLASS wndclass; ... wndclass.lpfnWndProc =WndProc; wndclass.lpszClassName = szWindowClass; ... RegisterClass(&wndclass); hWnd = CreateWindow( szWindowClass, ...); ... } LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { switch(message) { ... return; } return DefWindowProc(hwnd,message,wParam,lParam); }2.2 MFC中Message响应函数的安装 MFC中Message响应函数的安装显然更复杂,是在CWnd::CreateEx()被调用时完成的,其中还用到了Hook机制。 我们可以先猜一下MFC是怎么做的。MFC支持massage map,使得对消息的响应份散到多个message handler函数中,而不是API开发是那种集中式的消息处理函数;所以,想必会有专门的代码来负责“检索message map table然后调用message handle”。message map是为了支持程序员处理他关心的特殊message的,那么缺省的message处理逻辑在哪里呢?答案是MFC创建window obj时是用的“预定义的窗口类”,自然已经有了缺省的message处理函数。
从图中看到,CWnd有成员变量m_pfnSuper、成员变量m_hWnd、成员函数OnWndMsg()和成员函数DefWindowProc()。Wnd::OnWndMsg()负责“在message
map中定义的message handle”能否处理到来的message,如果处理了要返回true;CWnd::DefWindowProc()负责对message缺省处理。
5. frame work中的chain of responsability模式 下图是一个对象树,注意消息会在纵向和横向两个方向传播。
消息在横向方向上的传递,才是message route,才是chain of responsability模式,由多个相关类的OnCmdMsg()共同完成。
|