Win32 API是微软的操作系统Windows提供给开发人员的编程接口,它决定了我们开发的Windows应用程序的能力。MFC是微软为开发人员提供的类库,在某种意义上是对Win32 API的封装。本文试图从全局角度对Win32 API和MFC进行理解──给出二者的概念模型。
本文使用UML描述概念模型。Win32 API本不是面向对象的,我用面向对象的观点去理解它,无非是想表达其全局。
本文参考了MSDN、相关书籍和网上的一些资料,在此一并感谢。

一、Win32 API的概念模型

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。

从图中看到,gdi obj有8种,其中7种为:bmp,brush,pen,region,font,palette,path。另一种比较特殊的是DC,它可以被理解为一 种容器,程序员通过调用SelectPallette()将pallte放入容器,通过调用BeginPath()和EndPath()将path放入容 器,其它5种gdi obj,是通过调用SelectObject()放入容器的。DC又具体分为4种,其中DisplayDC就是最常用的用来支持我们“画Window”的 DC。 另外,如果觉得不好理解,请参考composite设计模式。

4、展开user obj部分

4.1 第1次迭代

window在Windows应用开发中占有重要地位。

从图中看到,window可分为3种:desktop,top-level window,child window。所有window被OS组织成tree,有专门的数据结构来管理。desktop就是树根,desktop的子节点是top-level window,top-level window的子节点是child window,child window仍然可以有子节点,同样归属于child window。tree数据结构中还记录了4种重要信息,是4种指针:parent指针、child指针、brother指针、owner指针。这样,从 任何一个window就能很容易地找到其它window了。

好了,暂且得到 window = desktop + topLevel + child 的结论,看看全局先。毕竟,一步到位有时候并不好。
从图中看到,window确实占有重要地位。从逻辑是讲,thread是window的拥有者;但是,所有window一起决定了屏幕看起来是上面样子, 何况点击任何一个window都会使window得相互覆盖关系发生变化,对所用window进行统一管理是必须的,所以OS又不得不统一用window tree来管理window,反映复杂的window关系。每个window都必须有一个且只能有一个客户区,还可能有一个title bar。 再来看看CreateWindow()函数的interface spec透露了哪些信息。
从图中看到,CreateWindow()负责为window建立与窗口类的联系。每个window都有一个窗口类与之对应,而一个窗口类可以对应多个 window。窗口类中记录了窗口函数和菜单等资源信息,而由file生成的module正是窗口函数和资源的老家。 4.2 第2次迭代

考察消息种类。

从图中看到,每个message都是发送给某个window的。注意,msg可由SYS代码产生,也可以由API函数产生。

进一步考察window,深入topLevel和child。


从图中看到,OVERLAPPED风格的window是top-level window的一种,而另一种POPUP风格的window从本质上(行为上)是特殊的一种OVERLAPPED风格的window,虽然我们从 coding的角度常常不这么认为。

还是不好,因为当我们调用CreateWindow() API函数时,明明感觉CHILD、OVERLAPPED、POPUP是“window style”。我再画一张图。

从图中看到,control必须是CHILD风格的,dialog必须是POPUP风格的,而一般性的window却可以是任意风格的。

4.3 第3次迭代

总结user obj:

CreateDialog()函数示意:

从图中看到,CreateDialog()和CreateWindow()最大的区别就是,它有对话框模板支持方便地定制dialog界面。注意,Dialog是特殊的window,窗口类它一定也是有的。


二、MFC的概念模型

前面我们研究了WIN32 API的“领域模型”,对它有较全面的认识。下面,对MFC概念模型的研究,我们把重点放在对app framework的研究上。
app framework中的message响应/传递机制是最重要的。而Hook机制和Message响应/传递机制是密切相关的,后者以前者为基础。

1. Hook机制

也许有些程序员只知道hook机制可以编写很“牛”的应用,孰不知MFC本身也是依靠hook机制的。

从图中看到,每个hook拥有一个指针队列,每个指针指向一个称为的HookProc函数,HookProc将在合适的时机被OS调用执行。hook是分 不同种类的,其实正是hook的种类决定了它什么时机被OS调用执行。提示,可以看一下“订阅-发布”设计模式以助理解。

2 MFC中Message响应函数的安装

2.1 回忆API中Message响应函数的安装

API中Message响应函数的安装,是由CreateWindow()实现的,它将window与一个windowClass联系起来,而后者中记录了Message响应函数的指针。
至于细节,看一下如何用Win32 SDK或Win16 SDK写程序就清楚了,其中 DefWindowProc()是API函数,负责提供缺省的消息处理,所以,程序员只需要handle需要特殊处理的消息。

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缺省处理。
执行过程是,首先CWnd::CreateEx()被调用,window obj和window class被相应建立,此时window class的WindowProc字段存储了预定义的缺省处理函数的地址;由于有hook在监听窗口创建消息,所以注册的hookProc()会被调用执 行,它将classWindow数据结构的WindowProc字段备份到CWnd::m_pfnSuper,再用SetWindowLong()改写 classWindow数据结构的WindowProc字段为::AfxWndProc()的地址。当任何一个message到达时,:: AfxWndProc()被调用,至于它的逻辑,聪明的你一定猜到了,先调用Wnd::OnWndMsg(),如果返回值为false,还要调用 CWnd::DefWindowProc(),CWnd::m_pfnSuper指向的缺省处理逻辑,也会在CWnd::DefWindowProc() 中被调用。
提示,上面其实有多态情况发生。比如你可以在搜一下pWnd->WindowProc(nMsg, wParam, lParam); 另外,OnWndMsg和DefWindowProc都是CWnd类的虚拟函数。

要是觉得不太好理解,最好在VC++里创建一个project实际跟踪一下,下面是我跟踪时调用栈映象的截图。

3. SubClass机制


从图中看到,SubClass机制以CWnd自身的m_pfnSuper为基础,和“MFC中Message响应函数的安装”很象。

4.frame work中的主要相关类

frame work中的主要相关类 就是 message route的候选人,正是它们的OnCmdMsg()共同完成了message route,形成了chain of responsability模式。

5. frame work中的chain of responsability模式

下图是一个对象树,注意消息会在纵向和横向两个方向传播。


消息在纵向方向上的传递,是在“上溯父类的massge map表”,MFC的message map完全是为了代替虚函数而采取的手段,而和message route无关。

消息在横向方向上的传递,才是message route,才是chain of responsability模式,由多个相关类的OnCmdMsg()共同完成。

三、 总结
从上面的讨论不难发现,MFC中用到了不少设计模式,如上面提到的chain of responsability模式、composite模式和“订阅-发布”模式。上面的讨论不仅有助于程序员全面掌握Win32 API和MFC,对architect frameborder="0" marginwidth=""><IFrame frameborder=0 marginwidth=0 marginheight=0 scrolling=no align=center src='http://www.blogbao.com/script.aspx?userid=45735&AdType=0&AdstyleID=46090&Direction=1' width=490 height=150 style='width:490;height:150'/>设计architecture也有很大帮助。<iframe width="490" scrolling="no" height="150" frameborder="0" align="middle" marginwidth="0" marginheight="0" src="http://www.blogbao.com/script.aspx?userid=45735&AdType=0&AdstyleID=46090&Direction=1" _fcksavedurl=""http://www.blogbao.com/script.aspx?userid=45735&AdType=0&AdstyleID=46090&Direction=1"" _fcksavedurl=""http://www.blogbao.com/script.aspx?userid=45735&AdType=0&AdstyleID=46090&Direction=1"" style="width: 490px; height: 150px;">

width="490" scrolling="no" height="150" frameborder="0" align="middle" style="width: 490px; height: 150px;" src="http://www.blogbao.com/script.aspx?userid=45735&AdType=0&AdstyleID=49847&Direction=1" marginheight="0" marginwidth="0">

系统理解Win32 API和MFC相关推荐

  1. MFC win32 API串口异步模式代码示范 vs2015

    MFC win32 API串口异步模式代码示范   vs2015 本程序为单步接收,即点击接收按钮,才能收到消息. 实时循环接收需要添加线程 参考实例: https://blog.csdn.net/t ...

  2. 使用Win32 API获取Windows系统主题色

    在Windows7以后增加了系统主题色的功能,这个功能一直延续到了Windows10.如图: 如果需要在程序中获取到这个颜色值,那么可以使用微软提供的一个Win32 API:DwmGetColoriz ...

  3. [Win32] API Hook(2)在64位系统上的实现

     本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/articl ...

  4. c#调用win32 API函数修改系统时间

    一般来说,系统时间的修改可以通过win32 API函数库中的SetLocalTime函数进行设置.对于C#语言来说,虽然win32 API大部分函数都已经封装在了.NET Framework类库中,但 ...

  5. MFC win32 API串口同步模式代码示范

    win32 API串口同步模式代码示范 源文件下载: vs2015打开 文件名: MFC_Win32API_同步串口.rar 在OnInitDialog()位置初始化串口: handleFile1 = ...

  6. Win32 API 封装类总结

    以下是一些封装的Win32 API类:备用: 重温WIN32 API ------ 最简单的Windows窗口封装类 http://blog.csdn.net/smstong/article/deta ...

  7. 揭示Win32 API拦截细节/API hooking revealed (1)

    原文出处:http://www.codeproject.com/system/hooksys.asp 简要介绍 拦截win32 API 调用对于多数windows开发人员来说都一直是很有挑战性的课题, ...

  8. java 调用win32 api 学习总结

    java使用JInvoke调用windows API 使用jinvoke调用windowsAPI.jna使用比较麻烦,需要写c代码和参数转换,jinvoke的使用就像jdk中的包一样. 官网使用参考: ...

  9. python getmenu不到菜单句柄,从弹出菜单win32 api Python中选择项目

    我在 Windows 7 64位机器上使用python 2.7(32位).我正在使用win32 Api自动执行一些Windows任务,我也是python和win32 api的新手.我看到了类似的问题, ...

最新文章

  1. 麦当劳数字化转型中获得的6个数据科学经验
  2. Tesorflow:module 'pandas.core.computation' has no attribute 'expressions'
  3. 720x576P时序参数图
  4. 计算机组成原理写一个运算器,计算机组成原理运算器的实现实验报告.doc
  5. 万圣节海报素材PSD分层模板
  6. 1.2 Filters
  7. 数据结构设计_数据结构算法设计题学起来很困难怎么破
  8. 安恒赛php_安恒强网杯部分web
  9. 关于直播,所有的技术细节都在这里了(一)
  10. Servlet 实现验证码
  11. 适合程序员的简历模板
  12. 软件工程 - 个人博客系统 - 概要设计与详细设计文档
  13. java home websphere_websphere6.1安装与配置
  14. Windows权限维持方法
  15. 综合运用(烤地瓜,搬家具)
  16. 超几何分布HyperGeometricDistribution
  17. 最新交易猫源码+独立后台管理
  18. Java拆分为姓和名
  19. supermap三维地下管线
  20. MUI移动端开发,嵌入ifream,页面返回问题解决

热门文章

  1. Jquery,Ready函数.
  2. 使用jquery第三方插件(生成曲线图)
  3. 尝试从远程计算机访问Web服务不显示调用按钮
  4. Loadrunner中web_reg_save_param的使用详解
  5. Gradle_04_解决多项目同级依赖时找不到符号的异常
  6. springboot-web进阶(三)——统一异常处理
  7. YouTube推荐系统算法梳理
  8. 通俗易懂!视觉slam第三部分——slam数学表示
  9. NeurIPS 2021揭榜,接收率创九年新高,中了吗中了吗?
  10. NewBeeNLP 年中 | From NewBee To NB