﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-lynda</title><link>http://www.cppblog.com/lynda/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 14 Apr 2026 23:08:37 GMT</lastBuildDate><pubDate>Tue, 14 Apr 2026 23:08:37 GMT</pubDate><ttl>60</ttl><item><title>系统理解Win32 API和MFC(转) </title><link>http://www.cppblog.com/lynda/archive/2010/10/16/130131.html</link><dc:creator>信陌如尘</dc:creator><author>信陌如尘</author><pubDate>Sat, 16 Oct 2010 07:12:00 GMT</pubDate><guid>http://www.cppblog.com/lynda/archive/2010/10/16/130131.html</guid><wfw:comment>http://www.cppblog.com/lynda/comments/130131.html</wfw:comment><comments>http://www.cppblog.com/lynda/archive/2010/10/16/130131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lynda/comments/commentRss/130131.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lynda/services/trackbacks/130131.html</trackback:ping><description><![CDATA[原文链接：<br><a href="http://www.vckbase.com/document/viewdoc/?id=487"><u><font color=#638f27>http://www.vckbase.com/document/viewdoc/?id=487</font></u></a>&nbsp; <strong>系统理解Win32 API和MFC(上)</strong><br><a href="http://www.vckbase.com/document/viewdoc/?id=488"><u><font color=#638f27>http://www.vckbase.com/document/viewdoc/?id=488</font></u></a>&nbsp; <strong>系统理解Win32 API和MFC(下)</strong><br><br><br>Win32 API是微软的操作系统Windows提供给开发人员的编程接口，它决定了我们开发的Windows应用程序的能力。MFC是微软为开发人员提供的类库，在某种意义上是对Win32 API的封装。本文试图从全局角度对Win32 API和MFC进行理解──给出二者的概念模型。<br>本文使用UML描述概念模型。Win32 API本不是面向对象的，我用面向对象的观点去理解它，无非是想表达其全局。 <br>本文参考了MSDN、相关书籍和网上的一些资料，在此一并感谢。<br><br><strong><img src="http://www.vckbase.com/document/image/paragraph.gif" width=14 height=16> 一、Win32 API的概念模型</strong><br><br>Win32 API的object有3种：user obj，gdi obj，kernel obj。但是，如果一点不考虑OS本身的支持，就会在有些问题上疑惑，因此，我这里把&#8220;operation system负责将中断封装成message&#8221;加上。<br><br><strong>1、user obj、gdi obj、kernel obj、system 4者的关系</strong> <br><br>由于是kernel obj部分负责将另外3者联系起来，因此我们在下图中直接深入到kernel obj部分内部。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC1.gif" width=793 height=586>&nbsp;<br>从图中看到，在内存中运行的，除了&#8220;负责将中断封装成message&#8221;的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。<br><br><strong>2、展开&#8220;system负责将中断封装成message&#8221;部分</strong><br><br>下面展开&#8220;system负责将中断封装成message&#8221;部分，尽早解除对&#8220;message到底是怎么形成的&#8221;的困惑。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC2.gif" width=736 height=362> <br><br><strong>3、展开&#8220;gdi obj&#8221;部分</strong>
<p>开发人员可以通过gdi obj将app的信息反馈给User。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC3.gif" width=814 height=527> <br>从图中看到，gdi obj有8种，其中7种为：bmp，brush，pen，region，font，palette，path。另一种比较特殊的是DC，它可以被理解为一种容器，程序员通过调用SelectPallette()将pallte放入容器，通过调用BeginPath()和EndPath()将path放入容器，其它5种gdi obj，是通过调用SelectObject()放入容器的。DC又具体分为4种，其中DisplayDC就是最常用的用来支持我们&#8220;画Window&#8221;的DC。 另外，如果觉得不好理解，请参考composite设计模式。<br><br><strong>4、展开user obj部分</strong></p>
<p><strong>4.1 第1次迭代</strong></p>
<p>window在Windows应用开发中占有重要地位。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC4.gif" width=815 height=625> <br>从图中看到，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了。</p>
好了，暂且得到 window = desktop + topLevel + child 的结论，看看全局先。毕竟，一步到位有时候并不好。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC5.gif" width=821 height=609> 从图中看到，window确实占有重要地位。从逻辑是讲，thread是window的拥有者；但是，所有window一起决定了屏幕看起来是上面样子，何况点击任何一个window都会使window得相互覆盖关系发生变化，对所用window进行统一管理是必须的，所以OS又不得不统一用window tree来管理window，反映复杂的window关系。每个window都必须有一个且只能有一个客户区，还可能有一个title bar。
<p>&nbsp;</p>
再来看看CreateWindow()函数的interface spec透露了哪些信息。
<p>&nbsp;</p>
<img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC6.gif" width=807 height=609><br>从图中看到，CreateWindow()负责为window建立与窗口类的联系。每个window都有一个窗口类与之对应，而一个窗口类可以对应多个window。窗口类中记录了窗口函数和菜单等资源信息，而由file生成的module正是窗口函数和资源的老家。
<p>&nbsp;</p>
<strong>4.2 第2次迭代</strong>
<p>考察消息种类。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC7.gif" width=822 height=572><br>从图中看到，每个message都是发送给某个window的。注意，msg可由SYS代码产生，也可以由API函数产生。<br><br>进一步考察window，深入topLevel和child。</p>
<p><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC8.gif" width=465 height=614><br>从图中看到，OVERLAPPED风格的window是top-level window的一种，而另一种POPUP风格的window从本质上(行为上)是特殊的一种OVERLAPPED风格的window，虽然我们从coding的角度常常不这么认为。 </p>
<p>还是不好，因为当我们调用CreateWindow() API函数时，明明感觉CHILD、OVERLAPPED、POPUP是&#8220;window style&#8221;。我再画一张图。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC9.gif" width=736 height=513> <br>从图中看到，control必须是CHILD风格的，dialog必须是POPUP风格的，而一般性的window却可以是任意风格的。<br><br><strong>4.3 第3次迭代</strong></p>
<p>总结user obj:<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC10.gif" width=819 height=615><br><br>CreateDialog()函数示意:<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC11.gif" width=753 height=617> </p>
<p>从图中看到，CreateDialog()和CreateWindow()最大的区别就是，它有对话框模板支持方便地定制dialog界面。注意，Dialog是特殊的window，窗口类它一定也是有的。<br><br><br><img src="http://www.vckbase.com/document/image/paragraph.gif" width=14 height=16><strong> 二、MFC的概念模型</strong></p>
<p>前面我们研究了WIN32 API的&#8220;领域模型&#8221;，对它有较全面的认识。下面，对MFC概念模型的研究，我们把重点放在对app framework的研究上。<br>app framework中的message响应/传递机制是最重要的。而Hook机制和Message响应/传递机制是密切相关的，后者以前者为基础。<br><br><strong>1. Hook机制</strong></p>
<p>也许有些程序员只知道hook机制可以编写很&#8220;牛&#8221;的应用，孰不知MFC本身也是依靠hook机制的。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC12.gif" width=820 height=581> <br>从图中看到，每个hook拥有一个指针队列，每个指针指向一个称为的HookProc函数，HookProc将在合适的时机被OS调用执行。hook是分不同种类的，其实正是hook的种类决定了它什么时机被OS调用执行。提示，可以看一下&#8220;订阅-发布&#8221;设计模式以助理解。<br><br><strong>2 MFC中Message响应函数的安装</strong></p>
<p><strong>2.1 回忆API中Message响应函数的安装</strong></p>
<p>API中Message响应函数的安装，是由CreateWindow()实现的，它将window与一个windowClass联系起来，而后者中记录了Message响应函数的指针。<br>至于细节，看一下如何用Win32 SDK或Win16 SDK写程序就清楚了，其中 DefWindowProc()是API函数，负责提供缺省的消息处理，所以，程序员只需要handle需要特殊处理的消息。</p>
<pre>int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
WNDCLASS wndclass;
...
wndclass.lpfnWndProc =WndProc;
wndclass.lpszClassName = szWindowClass;
...
RegisterClass(&amp;wndclass);
hWnd = CreateWindow( szWindowClass, ...);
...
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
...
return;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
</pre>
<p><strong>2.2 MFC中Message响应函数的安装 </strong></p>
<p>MFC中Message响应函数的安装显然更复杂，是在CWnd::CreateEx()被调用时完成的，其中还用到了Hook机制。</p>
<p>我们可以先猜一下MFC是怎么做的。MFC支持massage map，使得对消息的响应份散到多个message handler函数中，而不是API开发是那种集中式的消息处理函数；所以，想必会有专门的代码来负责&#8220;检索message map table然后调用message handle&#8221;。message map是为了支持程序员处理他关心的特殊message的，那么缺省的message处理逻辑在哪里呢？答案是MFC创建window obj时是用的&#8220;预定义的窗口类&#8221;，自然已经有了缺省的message处理函数。</p>
<p><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC13.gif" width=567 height=786> </p>
<p>从图中看到，CWnd有成员变量m_pfnSuper、成员变量m_hWnd、成员函数OnWndMsg()和成员函数DefWindowProc()。Wnd::OnWndMsg()负责&#8220;在message map中定义的message handle&#8221;能否处理到来的message，如果处理了要返回true；CWnd::DefWindowProc()负责对message缺省处理。<br>执行过程是，首先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()中被调用。<br>提示，上面其实有多态情况发生。比如你可以在搜一下pWnd-&gt;WindowProc(nMsg, wParam, lParam); 另外，OnWndMsg和DefWindowProc都是CWnd类的虚拟函数。<br><br>要是觉得不太好理解，最好在VC++里创建一个project实际跟踪一下，下面是我跟踪时调用栈映象的截图。<br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC14.gif" width=607 height=271><br><br><strong>3. SubClass机制</strong></p>
<p><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC15.gif" width=819 height=547><br>从图中看到，SubClass机制以CWnd自身的m_pfnSuper为基础，和&#8220;MFC中Message响应函数的安装&#8221;很象。<br><br><strong>4.frame work中的主要相关类</strong><br><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC16.gif" width=572 height=612> <br>frame work中的主要相关类 就是 message route的候选人，正是它们的OnCmdMsg()共同完成了message route，形成了chain of responsability模式。<br></p>
<p><strong>5. frame work中的chain of responsability模式</strong></p>
<p>下图是一个对象树，注意消息会在纵向和横向两个方向传播。</p>
<p><img src="http://www.vckbase.com/document/journal/vckbase16/images/API_MFC17.gif" width=823 height=419><br>消息在纵向方向上的传递，是在&#8220;上溯父类的massge map表&#8221;，MFC的message map完全是为了代替虚函数而采取的手段，而和message route无关。</p>
<p>消息在横向方向上的传递，才是message route，才是chain of responsability模式，由多个相关类的OnCmdMsg()共同完成。</p>
<p><strong><img src="http://www.vckbase.com/document/image/paragraph.gif" width=14 height=16> 三、 总结</strong><br>从上面的讨论不难发现，MFC中用到了不少设计模式，如上面提到的chain of responsability模式、composite模式和&#8220;订阅-发布&#8221;模式。上面的讨论不仅有助于程序员全面掌握Win32 API和MFC，对architect设计architecture也有很大帮助。</p>
<img src ="http://www.cppblog.com/lynda/aggbug/130131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lynda/" target="_blank">信陌如尘</a> 2010-10-16 15:12 <a href="http://www.cppblog.com/lynda/archive/2010/10/16/130131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>寻找数组中的最大值和最小值 </title><link>http://www.cppblog.com/lynda/archive/2010/10/16/130130.html</link><dc:creator>信陌如尘</dc:creator><author>信陌如尘</author><pubDate>Sat, 16 Oct 2010 07:11:00 GMT</pubDate><guid>http://www.cppblog.com/lynda/archive/2010/10/16/130130.html</guid><wfw:comment>http://www.cppblog.com/lynda/comments/130130.html</wfw:comment><comments>http://www.cppblog.com/lynda/archive/2010/10/16/130130.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/lynda/comments/commentRss/130130.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/lynda/services/trackbacks/130130.html</trackback:ping><description><![CDATA[<div class=blog_content>转发：<a href="http://kmplayer.javaeye.com/blog/769284"><u><font color=#6faf30>http://kmplayer.javaeye.com/blog/769284</font></u></a><br><br>1，可以将者看成两个独立的问题。 <br>个需要比较N次，需要比较2*N次。 <br><br>2，我们可以两两分组。 <br>每一对中较小的放左边，较大放右边。 N/2次。 <br>奇数位比较N/2次，找到最小值。 <br>偶数位比较N/2次，找到最大值。 <br>总的比较次数：1.5N。 <br>缺点：破坏了原数组。 <br><br>3，维持两个变量min和max。 <br>取出两个数，相比较1次。 <br>较小的和min比较，决定是否更新min。 <br>同理，更新max。 <br>可见处理两个数，比较3次。 <br>总的比较次数：1.5N <br>优点：不会破坏原来的数组。 <br><br>4，分治思想 <br>
<div class=dp-highlighter>
<div class=bar>
<div class=tools>C++代码 <a title=复制代码 onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://kmplayer.javaeye.com/blog/769284#"><img alt=复制代码 src="http://kmplayer.javaeye.com/images/icon_copy.gif"></a></div>
</div>
<ol class=dp-cpp>
    <li><span><span class=preprocessor><font color=#808080>#include&nbsp;&lt;iostream&gt; </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>using</font></strong></span><span>&nbsp;</span><span class=keyword><strong><font color=#7f0055>namespace</font></strong></span><span>&nbsp;std; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=keyword><strong><font color=#7f0055>void</font></strong></span><span>&nbsp;maxmin(</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;a[],</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;low,</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;high,</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&amp;&nbsp;max,</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&amp;&nbsp;min)&nbsp;</span><span class=comment><font color=#008200>//引用作为参数的强大作用 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;k,&nbsp;max1,min1,max2,min2; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>if</font></strong></span><span>(high-low==1||high-low==0) &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[low]&gt;a[high]?&nbsp;(max&nbsp;=&nbsp;a[low],&nbsp;min&nbsp;=&nbsp;a[high]):(max&nbsp;=&nbsp;a[high],&nbsp;min&nbsp;=&nbsp;a[low]); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>else</font></strong></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k=(high+low)/2; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxmin(&nbsp;a,low,k,max1,min1); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxmin(&nbsp;a,k+1,high,max2,min2); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment><font color=#008200>//一层比较两次 </font></span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max=max1&gt;max2?&nbsp;max1:max2; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min=min1&lt;min2?&nbsp;min1:min2; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span></span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;main() &nbsp;&nbsp;</span></span>
    <li><span>{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;max,min; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;data[]={8,3,6,2,1,9,4,5,7}; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=datatypes><strong><font color=#2e8b57>int</font></strong></span><span>&nbsp;num=</span><span class=keyword><strong><font color=#7f0055>sizeof</font></strong></span><span>(data)/</span><span class=keyword><strong><font color=#7f0055>sizeof</font></strong></span><span>(data[0]); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;maxmin(data,0,num-1,max,min); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class=string><font color=#0000ff>"最大值:"</font></span><span>&lt;&lt;max&lt;&lt;endl; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;</span><span class=string><font color=#0000ff>"最小值:"</font></span><span>&lt;&lt;min&lt;&lt;endl; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword><strong><font color=#7f0055>return</font></strong></span><span>&nbsp;0; &nbsp;&nbsp;</span></span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
复杂度分析： <br><br>f(2) = 1; <br>f(n) = 2*f(n/2) + 2; (注：一层需要比较两次) <br>可以推出f(n) = 1.5*n -2; <br>可见总的比较次数仍然没有减少。 <br></div>
<img src ="http://www.cppblog.com/lynda/aggbug/130130.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/lynda/" target="_blank">信陌如尘</a> 2010-10-16 15:11 <a href="http://www.cppblog.com/lynda/archive/2010/10/16/130130.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>