﻿<?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++博客-时间的痕迹-文章分类-MFC技术</title><link>http://www.cppblog.com/ivenher/category/246.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 13:01:52 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 13:01:52 GMT</pubDate><ttl>60</ttl><item><title>利用VC从DLL传递消息到EXE </title><link>http://www.cppblog.com/ivenher/articles/37002.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Tue, 20 Nov 2007 04:18:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/37002.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/37002.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/37002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/37002.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/37002.html</trackback:ping><description><![CDATA[&nbsp;在进行DLL开发过程中，尤其在进行底层硬件开发过程中，比如实时接收数据，进程需要和应用程序进行交互，而DLL和应用程序最好的交互就是发消息了，在DLL中定义消息的方式和在应用程序中定义消息的方式非常相似。下面谈谈这两种定义的方法：
<p>&#160;</p>
<p>&nbsp; 一、在应用程序自定义消息方法：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般自定义消息有一定的范围，虽然说自定义消息从WM_USER开始，但是由于我们的工程里面一般还有很多其他的控件，他们也要占用一部分WM_USER消息范围，所以我们必须为他们留出一部分范围，这里，我们保留100个消息，一般情况下，这可以满足我们的要求。</p>
<p>&nbsp; (1)&nbsp;&nbsp;&nbsp; 定义消息的值。在我们要发生消息的地方(例如CMyView.cpp的开始部分)或者stdafx..h文件，进行如下定义：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>#define WM_MSG&nbsp; (WM_USER+101)</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来的工作其实很简单，我们在前面说了，消息正常工作有3个部分必须协调：消息声明、消息映射、消息体。我们就一次进行手工加入。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)首先在AFX_MSG块中加入消息声明：在CMyView.h中，找到如下部分，并加入消息声明：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // {{AFX_MSG（CMyView)</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; afx_msg LRESULT OnMyMsg(WPARAM wParam,LPARAM lParam);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="file://}}AFX_MSG/"><u><font color=#0000ff>file://}}AFX_MSG</font></u></a> </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3)在MESSAGE_MAP块中添加ON_MESSAGE宏指令：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN_MESSAGE_MAP(CMyView, CView) </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="file://{{AFX_MSG_MAP(CMyView/"><u><font color=#0000ff>file://{{AFX_MSG_MAP(CMyView</font></u></a>) </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .....</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ON_MESSAGE(WM_MSG, OnMyMsg) </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="file://}}AFX_MSG_MAP/"><u><font color=#0000ff>file://}}AFX_MSG_MAP</font></u></a> </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END_MESSAGE_MAP() </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (4)添加消息函数体：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPESULT CMyView::OnMyMsg(WPARAM wParam, LPARAM lParam)
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox("消息已经收到！"); </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0; </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 消息至此就已经定义完毕，接下来我们就可以激活消息了，就可以用我们前面所说的PostMessage/SendMessage来发送消息了。</p>
<p>　　　　如：::PostMessage(hwnd,WM_MSG,0,1);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PostMessage:不用等消息返回。</p>
<p>　　　 SendMessage:需要等消息返回。</p>
<p>&nbsp; 二、从DLL中传递消息到EXE</p>
<p>　　　在DLL中定义消息和上面的方法很相似，有两点不同的地方：</p>
<p>&nbsp; 1、&nbsp; 在DLL和应用程序中两个地方定义相同的消息。</p>
<p>&nbsp; 2、&nbsp; 应用程序调用DLL程序之后，需要将应用程序的窗口句柄传递给DLL，以便DLL中的消息返回。</p>
<p>&nbsp; 在DLL工程中：</p>
<p>&nbsp; （1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在stdafx.h头文件中添加消息定义：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>&nbsp;#define WM_MSG WM_USER + 102</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　　　　　　</p>
<p>&nbsp; （2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加启动消息的输出函数：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>　　　　　　　CMessageDLLApp theApp;</p>
            <p>&nbsp; //发送消息</p>
            <p>extern "C" _declspec(dllexport) void StartSendMessage(HWND hwnd)</p>
            <p>{</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; theApp.SendMessage(hwnd);</p>
            <p>}　　　　　</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中hwnd是接收消息的窗口句柄。</p>
<p>&nbsp; （3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加启动消息的实现函数：</p>
<p>在头文件中添加函数声明：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>&nbsp; void SendMessage(HWND hwnd);</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp; 在CPP文件中添加函数实现</p>
<p>&nbsp; //启动发送消息</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>void CMessageDLLApp::SendMessage(HWND hwnd)</p>
            <p>{</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::PostMessage(hwnd,WM_MSG,0,1);</p>
            <p>}</p>
            <p>&nbsp; 在应</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>用程序中：</p>
<p>&nbsp; （1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在stdafx.h头文件中添加消息定义：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>#define WM_MSG WM_USER + 102</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　　　　　　 </p>
<p>&nbsp; （2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先在AFX_MSG块中加入消息声明：在CTestMessageDLLDlg.h中，找到如下部分，并加入消息声明：</p>
<p>。。。。。。</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>　　　　　　　 afx_msg LRESULT OnMyMsg(WPARAM wParam,LPARAM lParam);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE_MESSAGE_MAP()</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp; （3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在MESSAGE_MAP块中添加ON_MESSAGE宏指令：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>　　　　　　　 BEGIN_MESSAGE_MAP(CTestMessageDLLDlg, CDialog)</p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　。。。。。。</p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　ON_MESSAGE(WM_MSG, OnMyMsg) </p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　//}}AFX_MSG_MAP</p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　END_MESSAGE_MAP()</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp; （4）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加消息函数体：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>　　　　　　 LRESULT CTestMessageDLLDlg::OnMyMsg(WPARAM wParam, LPARAM lParam)
            <p>&nbsp;{ <br></p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　 AfxMessageBox("消息已经收到！"); </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　 return 0; </p>
            <p>&nbsp;　　　　}</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>　（5）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在对话框上添加一个按钮，在按钮事件中，先调用DLL文件，然后发送一个测试消息响应的命令：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>void CTestMessageDLLDlg::OnBnClickedButton1()</p>
            <p>{</p>
            <p>&nbsp;&nbsp;&nbsp; // TODO: 在此添加控件通知处理程序代码</p>
            <p>&nbsp;&nbsp;&nbsp; //定义函数</p>
            <p>&nbsp;&nbsp;&nbsp; typedef void (_cdecl*STARTSENDMESSAGE)(HWND hwnd);</p>
            <p>&nbsp;&nbsp;&nbsp; HMODULE hmessage = NULL;</p>
            <p>&nbsp;&nbsp;&nbsp; STARTSENDMESSAGE StartSendMessage = NULL;</p>
            <p>　　//导入DLL库文件</p>
            <p>&nbsp;&nbsp;&nbsp; hmessage = LoadLibrary("MessageDLL.dll");</p>
            <p>&nbsp;&nbsp;&nbsp; if(hmessage==NULL)</p>
            <p>&nbsp;&nbsp;&nbsp; {</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeLibrary(hmessage);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(0);</p>
            <p>&nbsp;&nbsp;&nbsp; }</p>
            <p>　　//导入DLL中测试消息函数</p>
            <p>&nbsp;&nbsp;&nbsp; StartSendMessage = (STARTSENDMESSAGE)GetProcAddress(hmessage,"StartSendMessage");</p>
            <p>&nbsp;&nbsp;&nbsp; if(StartSendMessage==NULL)</p>
            <p>&nbsp;&nbsp;&nbsp; {</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeLibrary(hmessage);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(1);</p>
            <p>&nbsp;&nbsp;&nbsp; }</p>
            <p>&nbsp;&nbsp;&nbsp; //获取对话框的窗口句柄</p>
            <p>&nbsp;&nbsp;&nbsp; HWND hwnd = this-＞GetSafeHwnd();</p>
            <p>&nbsp;&nbsp;&nbsp; //发送测试消息函数</p>
            <p>&nbsp;&nbsp;&nbsp; (*StartSendMessage)(hwnd);</p>
            <p>}</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>运行应用程序，就可以看到测试结果了。<br>&nbsp;<br></p>
<p><br><br><br><br><br clear=all></p>
<p><br><br><br></p>
<img src ="http://www.cppblog.com/ivenher/aggbug/37002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-11-20 12:18 <a href="http://www.cppblog.com/ivenher/articles/37002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CEdit 颜色设置</title><link>http://www.cppblog.com/ivenher/articles/21810.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 13 Apr 2007 08:50:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21810.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21810.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21810.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21810.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21810.html</trackback:ping><description><![CDATA[<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Color.h<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Colorref's&nbsp;to&nbsp;use&nbsp;with&nbsp;your&nbsp;Programs</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;RED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGB(127,&nbsp;&nbsp;0,&nbsp;&nbsp;0)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;GREEN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGB(&nbsp;&nbsp;0,127,&nbsp;&nbsp;0)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;BLUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGB(&nbsp;&nbsp;0,&nbsp;&nbsp;0,127)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;LIGHTRED&nbsp;&nbsp;&nbsp;RGB(255,&nbsp;&nbsp;0,&nbsp;&nbsp;0)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;LIGHTGREEN&nbsp;RGB(&nbsp;&nbsp;0,255,&nbsp;&nbsp;0)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;LIGHTBLUE&nbsp;&nbsp;RGB(&nbsp;&nbsp;0,&nbsp;&nbsp;0,255)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;BLACK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGB(&nbsp;&nbsp;0,&nbsp;&nbsp;0,&nbsp;&nbsp;0)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;WHITE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGB(255,255,255)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;GRAY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RGB(192,192,192)</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #808080">//////////////////////////////////////////</span><span style="COLOR: #008000">/</span><span style="COLOR: #808080"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #808080"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">color.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #808080">///////////////////////////////////////////////////////////////////////////</span><span style="COLOR: #008000">//</span><span style="COLOR: #808080"><br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #808080"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;CColorStatic&nbsp;window</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CColorStatic&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;CStatic<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Construction</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;SetTextColor(COLORREF&nbsp;crColor);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;This&nbsp;Function&nbsp;is&nbsp;to&nbsp;set&nbsp;the&nbsp;Color&nbsp;for&nbsp;the&nbsp;Text.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;SetBkColor(COLORREF&nbsp;crColor);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;This&nbsp;Function&nbsp;is&nbsp;to&nbsp;set&nbsp;the&nbsp;BackGround&nbsp;Color&nbsp;for&nbsp;the&nbsp;Text.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CColorStatic();<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Overrides<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;ClassWizard&nbsp;generated&nbsp;virtual&nbsp;function&nbsp;overrides<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">{{AFX_VIRTUAL(CColorStatic)<br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">}}AFX_VIRTUAL</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">CColorStatic();<br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Generated&nbsp;message&nbsp;map&nbsp;functions</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">{{AFX_MSG(CColorStatic)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">38</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">39</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CBrush&nbsp;m_brBkgnd;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Holds&nbsp;Brush&nbsp;Color&nbsp;for&nbsp;the&nbsp;Static&nbsp;Text</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">40</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;COLORREF&nbsp;m_crBkColor;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Holds&nbsp;the&nbsp;Background&nbsp;Color&nbsp;for&nbsp;the&nbsp;Text</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">41</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;COLORREF&nbsp;m_crTextColor;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Holds&nbsp;the&nbsp;Color&nbsp;for&nbsp;the&nbsp;Text</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">42</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">43</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;afx_msg&nbsp;HBRUSH&nbsp;CtlColor(CDC</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pDC,&nbsp;UINT&nbsp;nCtlColor);<br></span><span style="COLOR: #008080">44</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">}}AFX_MSG</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">45</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">46</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;DECLARE_MESSAGE_MAP()<br></span><span style="COLOR: #008080">47</span>&nbsp;<span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">48</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">49</span>&nbsp;<span style="COLOR: #000000"></span></div>
<br><br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;ColorEdit.cpp&nbsp;:&nbsp;implementation&nbsp;file<br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ColorEdit.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Color.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;File&nbsp;Holding&nbsp;(#define)'s&nbsp;for&nbsp;COLORREF&nbsp;Values</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">#ifdef&nbsp;_DEBUG<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;new&nbsp;DEBUG_NEW</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#undef</span><span style="COLOR: #000000">&nbsp;THIS_FILE</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;THIS_FILE[]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;__FILE__;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #808080">///////////////////////////////////////////////////////////////////////////</span><span style="COLOR: #008000">//</span><span style="COLOR: #808080"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #808080"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;CColorEdit</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">CColorEdit::CColorEdit()<br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_crBkColor&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;::GetSysColor(COLOR_3DFACE);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Initializing&nbsp;background&nbsp;color&nbsp;to&nbsp;the&nbsp;system&nbsp;face&nbsp;color.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_crTextColor&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;BLACK;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Initializing&nbsp;text&nbsp;color&nbsp;to&nbsp;black</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_brBkgnd.CreateSolidBrush(m_crBkColor);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Creating&nbsp;the&nbsp;Brush&nbsp;Color&nbsp;For&nbsp;the&nbsp;Edit&nbsp;Box&nbsp;Background</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">CColorEdit::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">CColorEdit()<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000">BEGIN_MESSAGE_MAP(CColorEdit,&nbsp;CEdit)<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">{{AFX_MSG_MAP(CColorEdit)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;ON_WM_CTLCOLOR_REFLECT()<br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">}}AFX_MSG_MAP</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">END_MESSAGE_MAP()<br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #808080">///////////////////////////////////////////////////////////////////////////</span><span style="COLOR: #008000">//</span><span style="COLOR: #808080"><br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #808080"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;CColorEdit&nbsp;message&nbsp;handlers</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">38</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CColorEdit::SetTextColor(COLORREF&nbsp;crColor)<br></span><span style="COLOR: #008080">39</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">40</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_crTextColor&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;crColor;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Passing&nbsp;the&nbsp;value&nbsp;passed&nbsp;by&nbsp;the&nbsp;dialog&nbsp;to&nbsp;the&nbsp;member&nbsp;varaible&nbsp;for&nbsp;Text&nbsp;Color</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">41</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;RedrawWindow();<br></span><span style="COLOR: #008080">42</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">43</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">44</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;CColorEdit::SetBkColor(COLORREF&nbsp;crColor)<br></span><span style="COLOR: #008080">45</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">46</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_crBkColor&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;crColor;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Passing&nbsp;the&nbsp;value&nbsp;passed&nbsp;by&nbsp;the&nbsp;dialog&nbsp;to&nbsp;the&nbsp;member&nbsp;varaible&nbsp;for&nbsp;Backgound&nbsp;Color</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">47</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_brBkgnd.DeleteObject();&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Deleting&nbsp;any&nbsp;Previous&nbsp;Brush&nbsp;Colors&nbsp;if&nbsp;any&nbsp;existed.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">48</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;m_brBkgnd.CreateSolidBrush(crColor);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Creating&nbsp;the&nbsp;Brush&nbsp;Color&nbsp;For&nbsp;the&nbsp;Edit&nbsp;Box&nbsp;Background</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">49</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;RedrawWindow();<br></span><span style="COLOR: #008080">50</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">51</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">52</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">53</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">54</span>&nbsp;<span style="COLOR: #000000">HBRUSH&nbsp;CColorEdit::CtlColor(CDC</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pDC,&nbsp;UINT&nbsp;nCtlColor)<br></span><span style="COLOR: #008080">55</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">56</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;HBRUSH&nbsp;hbr;<br></span><span style="COLOR: #008080">57</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;hbr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(HBRUSH)m_brBkgnd;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Passing&nbsp;a&nbsp;Handle&nbsp;to&nbsp;the&nbsp;Brush</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">58</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;pDC</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">SetBkColor(m_crBkColor);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Setting&nbsp;the&nbsp;Color&nbsp;of&nbsp;the&nbsp;Text&nbsp;Background&nbsp;to&nbsp;the&nbsp;one&nbsp;passed&nbsp;by&nbsp;the&nbsp;Dialog</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">59</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;pDC</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">SetTextColor(m_crTextColor);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Setting&nbsp;the&nbsp;Text&nbsp;Color&nbsp;to&nbsp;the&nbsp;one&nbsp;Passed&nbsp;by&nbsp;the&nbsp;Dialog</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">60</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">61</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(nCtlColor)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;To&nbsp;get&nbsp;rid&nbsp;of&nbsp;compiler&nbsp;warning</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">62</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCtlColor&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">63</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">64</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hbr;<br></span><span style="COLOR: #008080">65</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">66</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">67</span>&nbsp;<span style="COLOR: #000000">BOOL&nbsp;CColorEdit::SetReadOnly(BOOL&nbsp;flag)<br></span><span style="COLOR: #008080">68</span>&nbsp;<span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">69</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(flag&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;TRUE)<br></span><span style="COLOR: #008080">70</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetBkColor(m_crBkColor);<br></span><span style="COLOR: #008080">71</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">72</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetBkColor(WHITE);<br></span><span style="COLOR: #008080">73</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">74</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;CEdit::SetReadOnly(flag);<br></span><span style="COLOR: #008080">75</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">76</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">77</span>&nbsp;<span style="COLOR: #000000"></span></div>
<img src ="http://www.cppblog.com/ivenher/aggbug/21810.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-13 16:50 <a href="http://www.cppblog.com/ivenher/articles/21810.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文本框字体色,对话框和静态文件背景色设置方法(OnCtlColor消息)</title><link>http://www.cppblog.com/ivenher/articles/21805.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 13 Apr 2007 08:23:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21805.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21805.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21805.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21805.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21805.html</trackback:ping><description><![CDATA[<p>重载 OnCtrlColor.<font face="Times New Roman" color=#000000 size=3><br><br>HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br>{<br>&nbsp;HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);<br>&nbsp;<br>&nbsp;if(nCtlColor == CTLCOLOR_DLG || nCtlColor == CTLCOLOR_STATIC)<br>&nbsp;{<br>&nbsp;&nbsp;//pDC-&gt;SetTextColor(RGB(0,0,255));//字体色<br>&nbsp;&nbsp;pDC-&gt;SetBkColor(RGB(210,230,211));//字体背景色******<br>&nbsp;&nbsp;HBRUSH B = CreateSolidBrush(RGB(210,230,211)); //背景色<br>&nbsp;&nbsp;return B;<br>&nbsp;}<br>&nbsp;if(nCtlColor == CTLCOLOR_EDIT)<br>&nbsp;{<br>&nbsp;&nbsp;pDC-&gt;SetTextColor(RGB(0,0,255));//字体色<br>&nbsp;}</font></p>
<p><font face="Times New Roman" color=#000000 size=3>&nbsp;return hbr;<br>}</font></p>
<img src ="http://www.cppblog.com/ivenher/aggbug/21805.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-13 16:23 <a href="http://www.cppblog.com/ivenher/articles/21805.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很好的button类 实现文件 4</title><link>http://www.cppblog.com/ivenher/articles/21705.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 03:48:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21705.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21705.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21705.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21705.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21705.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;2&nbsp;//&nbsp;This&nbsp;function&nbsp;creates&nbsp;a&nbsp;grayscale&nbsp;icon&nbsp;starting&nbsp;from&nbsp;a&nbsp;given&nbsp;icon.&nbsp;&nbsp;3&nbsp;//&nbsp;The&nbsp;re...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/21705.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/21705.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 11:48 <a href="http://www.cppblog.com/ivenher/articles/21705.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很好的button类 实现文件 3</title><link>http://www.cppblog.com/ivenher/articles/21703.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 03:47:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21703.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21703.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21703.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21703.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HBITMAP&nbsp;CButtonST::CreateBitmapMask(HBITMAP&nbsp;hSourceBitmap,&nbsp;DWORD&nbsp;dwWidth,&nbsp;DWORD&nbsp;dwHeight,&nbsp;COLORREF&nbsp;crTransColor){&nbsp;&nbsp;&nbsp;&nbsp;HBITMAP&nbsp;&nbsp;&nbs...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/21703.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/21703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 11:47 <a href="http://www.cppblog.com/ivenher/articles/21703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很好的button类 实现文件 2</title><link>http://www.cppblog.com/ivenher/articles/21702.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21702.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21702.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21702.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21702.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21702.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;2&nbsp;#ifdef&nbsp;&nbsp;&nbsp;&nbsp;BTNST_USE_BCMENU&nbsp;&nbsp;3&nbsp;LRESULT&nbsp;CButtonST::OnMenuChar(UINT&nbsp;nChar,&nbsp;UINT&nbsp;nFlags,&nbsp;CMenu*&nbsp;pMenu...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/21702.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/21702.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 11:46 <a href="http://www.cppblog.com/ivenher/articles/21702.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很好的button类 实现文件 1</title><link>http://www.cppblog.com/ivenher/articles/21701.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 03:45:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21701.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21701.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21701.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21701.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21701.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;1#include&nbsp;"stdafx.h"&nbsp;&nbsp;2#include&nbsp;"BtnST.h"&nbsp;&nbsp;3&nbsp;&nbsp;4#ifdef&nbsp;&nbsp;&nbsp;&nbsp;BTNST_USE_SOUND&nbsp;&nbsp;5#pragma&nbsp;comment(lib,&nbsp;"winmm.lib")...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/21701.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/21701.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 11:45 <a href="http://www.cppblog.com/ivenher/articles/21701.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>很好的button类  头文件</title><link>http://www.cppblog.com/ivenher/articles/21698.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 03:37:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21698.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21698.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21698.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21698.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: ////&nbsp;&nbsp;&nbsp;&nbsp;Class:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CButtonST////&nbsp;&nbsp;&nbsp;&nbsp;Compiler:&nbsp;&nbsp;&nbsp;&nbsp;Visual&nbsp;C++//&nbsp;&nbsp;&nbsp;&nbsp;Tested&...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/21698.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/21698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 11:37 <a href="http://www.cppblog.com/ivenher/articles/21698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>      CBitmapDialog 的使用</title><link>http://www.cppblog.com/ivenher/articles/21696.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 03:36:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21696.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21696.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21696.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21696.html</trackback:ping><description><![CDATA[<div twffan="done"><font face=Arial color=#ff0000 size=5>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CBitmapDialog 的使用</font></div>
<div twffan="done"><font face=Arial>在所有步骤之前，先添加按钮各个状态所需的位图资源。 </font></div>
<div twffan="done"><font face=Arial>1 &nbsp; 在对话框应用程序中添加Button1（ID为IDC_BUTTON1)。在属性的Style标签下选择Owner&nbsp; draw即可，不需要选择Bitmap属性！</font></div>
<div twffan="done"><font face=Arial>&nbsp; <br>2&nbsp; 在程序中定义一个CBitmapButton成员变量bmButton。不能使用ClassWizard为按钮映射一个CButton变量，然后改为CBitmapButton，这么做并不能将按钮直接映射为CBitmapButton类的对象，反而会出现初始化错误。 <br>&nbsp;<br>3&nbsp; 使用CBitmapButton::LoadBitmaps装载各种状态的图片,使用SubclassDlgItem关联到想要的按钮，使用CBitmapButton::SizeToContent函数使按钮适合图片大小。注意Loadbitmaps一定要在关联到按钮之前进行！&nbsp; </font></div>
<font face=Arial>
<div twffan="done"><br>在OnInitDialog()中添加的代码如下所示：</div>
<div twffan="done">BOOL CCBitmapDlgDlg::OnInitDialog()<br>{<br>&nbsp;CDialog::OnInitDialog();</div>
<div twffan="done">&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //.........................<br>&nbsp;<br>&nbsp;<br>&nbsp;// TODO: Add extra initialization here<br>if(bmButton.LoadBitmaps(IDB_BITMAP_QI,IDB_BITMAP1,IDB_BITMAP2,IDB_BITMAP2)==0)<br>MessageBox("装载位图出错！");<br>bmButton.SubclassDlgItem(IDC_BUTTON1,AfxGetMainWnd());</div>
<div twffan="done">&nbsp;bmButton.SizeToContent();</div>
<div twffan="done"><br>return TRUE;&nbsp; // return TRUE&nbsp; unless you set the focus to a control<br>}</div>
<div twffan="done">//对LoadBitmaps( ) 的一点说明：&nbsp; <br>第一个参数为按钮没有按下时（UP）的位图。<br>第二个参数为按钮按下时（DOWM ）的位图。<br>第三个参数为按钮是焦点时（Focused）的位图。<br>第四个参数为按钮不可用时（Disabled）的位图。</div>
</font>
<img src ="http://www.cppblog.com/ivenher/aggbug/21696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 11:36 <a href="http://www.cppblog.com/ivenher/articles/21696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CFormView 设置背景色</title><link>http://www.cppblog.com/ivenher/articles/21685.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 12 Apr 2007 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21685.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21685.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21685.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21685.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21685.html</trackback:ping><description><![CDATA[<br><br>给类CXXFormView添加一个CBrush类的成员变量m_brush &nbsp; <br>&nbsp; 然后在其构造函数中加m_brush.CreateSolidBrush(RGB(255,255,255)); &nbsp; <br>&nbsp; 如我的CXXFormView类 &nbsp; <br>&nbsp; CPackInterView::CPackInterView() &nbsp; <br>&nbsp; : &nbsp; CFormView(CPackInterView::IDD) &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; //{{AFX_DATA_INIT(CPackInterView) &nbsp; <br>&nbsp; //}}AFX_DATA_INIT &nbsp; <br>&nbsp; m_brush.CreateSolidBrush(RGB(255,255,255));//设为白色 &nbsp; <br>&nbsp; } &nbsp; <br>&nbsp; 接着映射一个WM_CTLCOLOR消息，在ClassWizard中添加.在OnCtlColor中如下设置即可 &nbsp; <br>&nbsp; HBRUSH &nbsp; CPackInterView::OnCtlColor(CDC* &nbsp; pDC, &nbsp; CWnd* &nbsp; pWnd, &nbsp; UINT &nbsp; nCtlColor) &nbsp; &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; HBRUSH &nbsp; hbr &nbsp; = &nbsp; CFormView::OnCtlColor(pDC, &nbsp; pWnd, &nbsp; nCtlColor); &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; // &nbsp; TODO: &nbsp; Change &nbsp; any &nbsp; attributes &nbsp; of &nbsp; the &nbsp; DC &nbsp; here &nbsp; <br>&nbsp; if(nCtlColor==CTLCOLOR_DLG) &nbsp; <br>&nbsp; return &nbsp; (HBRUSH)m_brush.GetSafeHandle(); &nbsp; <br>&nbsp; // &nbsp; TODO: &nbsp; Return &nbsp; a &nbsp; different &nbsp; brush &nbsp; if &nbsp; the &nbsp; default &nbsp; is &nbsp; not &nbsp; desired &nbsp; <br>&nbsp; return &nbsp; hbr; &nbsp; <br>&nbsp; }&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp; <br>
<img src ="http://www.cppblog.com/ivenher/aggbug/21685.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-12 10:19 <a href="http://www.cppblog.com/ivenher/articles/21685.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>滚动条位置</title><link>http://www.cppblog.com/ivenher/articles/21596.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Tue, 10 Apr 2007 06:02:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21596.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21596.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21596.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21596.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21596.html</trackback:ping><description><![CDATA[在ListBox中怎么样才能使右边的垂直滚动条一直处于列表框的最下端<br><br>int &nbsp; iMinPos &nbsp; = &nbsp; 0; &nbsp; <br>&nbsp; int &nbsp; iMaxPos &nbsp; = &nbsp; 0; &nbsp; <br>&nbsp; m_nInfoList.GetScrollRange(SB_VERT, &nbsp; &amp;iMinPos, &nbsp; &amp;iMaxPos); &nbsp; <br>&nbsp; m_nInfoList.SetScrollPos(SB_VERT, &nbsp; iMaxPos, &nbsp; TRUE); &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 这样的话，滚条是一直都在底端了，但最新的内容没有显示在最底端(所见部分的最底端).<br><br>CEdit<br><br>&nbsp; int&nbsp;&nbsp; iMinPos&nbsp;&nbsp; =&nbsp;&nbsp; 0;&nbsp;&nbsp; <br>&nbsp; int&nbsp;&nbsp; iMaxPos&nbsp;&nbsp; =&nbsp;&nbsp; 0;&nbsp;&nbsp; <br>&nbsp; m_edit.GetScrollRange(SB_VERT,&nbsp;&nbsp; &amp;iMinPos,&nbsp;&nbsp; &amp;iMaxPos);&nbsp;&nbsp; <br>&nbsp; //m_edit.SetScrollPos(SB_VERT,&nbsp;&nbsp; iMaxPos,&nbsp;&nbsp; TRUE);&nbsp;<br>&nbsp;&nbsp;&nbsp;m_edit.LineScroll(iMaxPos);&nbsp;&nbsp;// Select LAST LINE
<img src ="http://www.cppblog.com/ivenher/aggbug/21596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-10 14:02 <a href="http://www.cppblog.com/ivenher/articles/21596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vc6 转换到  vc7的一点问题</title><link>http://www.cppblog.com/ivenher/articles/21308.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 05 Apr 2007 05:23:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/21308.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/21308.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/21308.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/21308.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/21308.html</trackback:ping><description><![CDATA[.H &nbsp; <br>&nbsp; // &nbsp; Generated &nbsp; message &nbsp; map &nbsp; functions &nbsp; <br>&nbsp; //{{AFX_MSG(CConnectThread) &nbsp; <br>&nbsp; //}}AFX_MSG &nbsp; <br>&nbsp; afx_msg &nbsp; LRESULT &nbsp; OnThreadMessage(WPARAM &nbsp; wParam, &nbsp; LPARAM &nbsp; lParam); &nbsp; <br>&nbsp; DECLARE_MESSAGE_MAP() &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; .CPP &nbsp; <br>&nbsp; BEGIN_MESSAGE_MAP(CConnectThread, &nbsp; CWinThread) &nbsp; <br>&nbsp; //{{AFX_MSG_MAP(CConnectThread) &nbsp; <br>&nbsp; //}}AFX_MSG_MAP &nbsp; <br>&nbsp; ON_MESSAGE(WM_THREADMSG, &nbsp; OnThreadMessage)----出错 &nbsp; <br>&nbsp; //ON_THREAD_MESSAGE(WM_THREADMSG, &nbsp; OnThreadMessage) &nbsp; <br>&nbsp; END_MESSAGE_MAP() &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; afx_msg &nbsp; LRESULT &nbsp; CConnectThread::OnThreadMessage(WPARAM &nbsp; wParam, &nbsp; LPARAM &nbsp; lParam) &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; switch(wParam) &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; case &nbsp; 0: &nbsp; // &nbsp; destroy &nbsp; data &nbsp; socket &nbsp; <br>&nbsp; m_ConnectSocket.DestroyDataConnection(); &nbsp; <br>&nbsp; break; &nbsp; <br>&nbsp; case &nbsp; 1: &nbsp; // &nbsp; quit &nbsp; ! &nbsp; <br>&nbsp; PostThreadMessage(WM_QUIT,0,0); &nbsp; <br>&nbsp; break; &nbsp; <br>&nbsp; default: &nbsp; <br>&nbsp; break; &nbsp; <br>&nbsp; } &nbsp; <br>&nbsp; return &nbsp; 0L; &nbsp; <br>&nbsp; } &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; d:\ConnectThread.cpp(146) &nbsp; : &nbsp; error &nbsp; C2440: &nbsp; &#8220;static_cast&#8221; &nbsp; : &nbsp; 无法从&#8220;LRESULT &nbsp; (__thiscall &nbsp; CConnectThread::* &nbsp; )(WPARAM,LPARAM)&#8221;转换为&#8220;LRESULT &nbsp; (__thiscall &nbsp; CWnd::* &nbsp; )(WPARAM,LPARAM)&#8221;&nbsp;&nbsp; <br><br>／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／<br>void &nbsp; OnThreadMessage(WPARAM &nbsp; wParam, &nbsp; LPARAM &nbsp; lParam); &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; DECLARE_MESSAGE_MAP() &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; .CPP &nbsp; <br>&nbsp; BEGIN_MESSAGE_MAP(CConnectThread, &nbsp; CWinThread) &nbsp; <br>&nbsp; //{{AFX_MSG_MAP(CConnectThread) &nbsp; <br>&nbsp; //}}AFX_MSG_MAP &nbsp; <br>&nbsp; //ON_MESSAGE(WM_THREADMSG, &nbsp; OnThreadMessage)----出错 &nbsp; <br>&nbsp; ON_THREAD_MESSAGE(WM_THREADMSG, &nbsp; OnThreadMessage) &nbsp; <br>&nbsp; END_MESSAGE_MAP() &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; void &nbsp; CConnectThread::OnThreadMessage(WPARAM &nbsp; wParam, &nbsp; LPARAM &nbsp; lParam) &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; switch(wParam) &nbsp; <br>&nbsp; { &nbsp; <br>&nbsp; case &nbsp; 0: &nbsp; // &nbsp; destroy &nbsp; data &nbsp; socket &nbsp; <br>&nbsp; m_ConnectSocket.DestroyDataConnection(); &nbsp; <br>&nbsp; break; &nbsp; <br>&nbsp; case &nbsp; 1: &nbsp; // &nbsp; quit &nbsp; ! &nbsp; <br>&nbsp; PostThreadMessage(WM_QUIT,0,0); &nbsp; <br>&nbsp; break; &nbsp; <br>&nbsp; default: &nbsp; <br>&nbsp; break; &nbsp; <br>&nbsp; } &nbsp; <br>&nbsp; return; &nbsp; <br>&nbsp; }&nbsp;&nbsp; <br>／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／<br><br><br>
<img src ="http://www.cppblog.com/ivenher/aggbug/21308.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-04-05 13:23 <a href="http://www.cppblog.com/ivenher/articles/21308.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC 多文档用户界面设计 </title><link>http://www.cppblog.com/ivenher/articles/20746.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Wed, 28 Mar 2007 01:32:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/20746.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/20746.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/20746.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/20746.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/20746.html</trackback:ping><description><![CDATA[     <span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">用习惯了</span><span lang="EN-US" twffan="done">Delphi</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">、</span><span lang="EN-US" twffan="done">VB</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">、</span><span lang="EN-US" twffan="done">Windows Form</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">（</span><span lang="EN-US" twffan="done">Visual C#</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">）等称之为</span><span lang="EN-US" twffan="done">RAD</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">（</span><span lang="EN-US" twffan="done">Rapid Application Development</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">）的开发工具进行项目开发的都会很满足这些工具和平台提供的快速界面开发的功效：你可以很容易就可以实现一个</span><span lang="EN-US" twffan="done">MIS</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">系统的管理界面，提供一个主框架，点击主框架上的某一个菜单项就打开一个处理事务的窗口，这些窗口可以重叠，可以最大</span><span lang="EN-US" twffan="done">/</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">小化，一切看起来都像那么回事。但是当你在</span><span lang="EN-US" twffan="done">VC</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">中进行开发的时候，发现整个世界都变了，虽然</span><span lang="EN-US" twffan="done">VC</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">提供了</span><span lang="EN-US" twffan="done">MDI</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">支持多文档视图的框架，但是每次你点击“打开”</span><span lang="EN-US" twffan="done">/</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">“新建”菜单项的时候，你会发现新打开的窗口千孔一面，都是同一个样式，根本就不能满足项目的开发。这就需要你能够为不同的业务逻辑提供不同的显示</span><span lang="EN-US" twffan="done">/</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">操作界面。这里给出一个模版，供大家参考：</span><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial" twffan="done">Step 1</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：使用</span><span lang="EN-US" twffan="done">VC 6.0</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">新建一个</span><span lang="EN-US" twffan="done">Project</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，命名为：</span><span lang="EN-US" twffan="done">MIS</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">。除选择单文档属性外，一切使用“默认”方式。于是你可以获得五个类：</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial" twffan="done">CMainFrame</span></b><span lang="EN-US" twffan="done"></span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial" twffan="done">CMISApp</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial" twffan="done">CMISDoc</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial" twffan="done">CMISView</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，和</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial" twffan="done">CAboutDlg</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span></span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial" twffan="done">Step 2</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：新建一套新的</span><span lang="EN-US" twffan="done">Doc/View/Frame</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：添加新类</span><span lang="EN-US" twffan="done">CNewDoc</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，基类为</span><span lang="EN-US" twffan="done">CDocument</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">（方法：</span><span lang="EN-US" twffan="done">Insert</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">——</span><span lang="EN-US" twffan="done">&gt;New Class</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">（</span><span lang="EN-US" twffan="done">Class Type</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：</span><span lang="EN-US" twffan="done">MFC Class</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">），基类选择</span><span lang="EN-US" twffan="done">CDocument</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">）。添加新的框架类</span><span lang="EN-US" twffan="done">CNewChildFrame</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，基类为</span><span lang="EN-US" twffan="done">CMDIChildWnd</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，添加方法同上。添加新的视图类</span><span lang="EN-US" twffan="done">CNewView</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，方法：</span><span lang="EN-US" twffan="done">Insert</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">——</span><span lang="EN-US" twffan="done">&gt;New Form</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，对话框中的文档类选择为</span><span lang="EN-US" twffan="done">CNewDoc</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">（默认也是）。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span></span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial" twffan="done">Step 3</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：将菜单资源</span><span lang="EN-US" twffan="done">IDR_MAINFRAME</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">中添加菜单项“功能”，并添加菜单子项“功能</span><?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /?><st1:chmetcnv w:st="on" unitname="”" sourcevalue="1" hasspace="False" negative="False" numbertype="1" tcsc="0"><span lang="EN-US" twffan="done">1</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">”</span></st1:chmetcnv><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">和“功能</span><st1:chmetcnv w:st="on" unitname="”" sourcevalue="2" hasspace="False" negative="False" numbertype="1" tcsc="0"><span lang="EN-US" twffan="done">2</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">”</span></st1:chmetcnv><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，分别对应项目开发中的不同的业务逻辑。为了保证整个过程中菜单项的一致性，在</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">IDR_MAINFRAME</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">上</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">Ctrl + C</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">，然后</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">Ctrl +V</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">两次生成和</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">IDR_MAINFRAME</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">一样的菜单两个，然后将这两个菜单分别改名为</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">IDR_MISTYPE</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">和</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">IDR_VIEW2_TMPL</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">（注意：先将后两个菜单名字</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">Copy</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">再删除它们，然后再改名，这里菜单的名字可以换，但是为了简单就直接使用系统生成的默认菜单名字，如果改变了名字要在</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">New CMultiDocTemplate</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">时刻修改相应项）。</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial" twffan="done">Step 4</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：在</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="COLOR: blue; FONT-FAMILY: Arial" twffan="done">CMISApp</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">中添加变量记录这两个框架类，为简单起见就声明为</span><span lang="EN-US" twffan="done">public</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">（方便后面的访问，也就懒得管面向对象的设计原则了，因为仅仅是示例而已）：</span></p><div align="center" twffan="done"><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #d9d9d9; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid green .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid green; mso-border-insidev: .5pt solid green" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 257.4pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" valign="top" width="343"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done">public</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span lang="EN-US" twffan="done">CMultiDocTemplate* m_pDocTemplate1;</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>CMultiDocTemplate* m_pDocTemplate2;</span></p></td></tr></tbody></table></div><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">并将</span><span lang="EN-US" twffan="done">BOOL CMISApp::InitInstance()</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">函数中由</span><span lang="EN-US" twffan="done">VC</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">自动生成的代码作如下改变：</span></p><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #d9d9d9; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid green .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid green; mso-border-insidev: .5pt solid green" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done">{<span style="mso-tab-count: 1" twffan="done">   </span>// BLOCK: doc template registration</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">     </span>// Register the document template.<span style="mso-spacerun: yes" twffan="done">  </span>Document templates serve</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">     </span>// as the connection between documents, frame windows and views.</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">     </span>// Attach this form to another document or frame window by changing</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">     </span>// the document or frame class in the constructor below.</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">     </span>CMultiDocTemplate* m_pDocTemplate2 = new CMultiDocTemplate(</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">            </span>IDR_VIEW2_TMPL,<span style="mso-spacerun: yes" twffan="done">          </span>//</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">这里就是菜单项目</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">            </span>RUNTIME_CLASS(CNewDoc),<span style="mso-tab-count: 2" twffan="done">          </span>// document class</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">            </span>RUNTIME_CLASS(CMDIChildWnd),<span style="mso-tab-count: 2" twffan="done">         </span>// frame class</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">            </span>RUNTIME_CLASS(CNewView));<span style="mso-tab-count: 2" twffan="done">        </span>// view class</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">     </span>AddDocTemplate(m_pDocTemplate2);</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><span lang="EN-US" twffan="done">}</span></p></td></tr><tr style="mso-yfti-irow: 1"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt; mso-border-top-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center"><span style="COLOR: red; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">改为</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：</span><span lang="EN-US" twffan="done">1</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">）（注意将</span><span lang="EN-US" twffan="done">CMultiDocTemplate*</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">去掉，否则你是新建了一个</span><span lang="EN-US" twffan="done">CMultiDocTemplate*</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">的对</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">象）</span><span lang="EN-US" twffan="done">2</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">）如果不是选用</span><span lang="EN-US" twffan="done">New Form </span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">则没有生成以上代码，则直接添加以下代码。</span></p></td></tr><tr style="mso-yfti-irow: 2; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt; mso-border-top-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.85pt; mso-char-indent-count: 1.7"><span lang="EN-US" twffan="done">m_pDocTemplate2 = new CMultiDocTemplate(</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-char-indent-count: 1.71"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done"></span>IDR_VIEW2_TMPL,</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-char-indent-count: 1.71"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done"></span>RUNTIME_CLASS(CNewDoc),<span style="mso-tab-count: 2" twffan="done">          </span>// document class</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-char-indent-count: 1.71"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done"></span>RUNTIME_CLASS(CNewChildFrame),<span style="mso-tab-count: 2" twffan="done">              </span>// frame class</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-char-indent-count: 1.71"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done"></span>RUNTIME_CLASS(CNewView));<span style="mso-tab-count: 2" twffan="done">        </span>// view class</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 17.95pt; mso-char-indent-count: 1.71"><span lang="EN-US" twffan="done">AddDocTemplate(m_pDocTemplate2);</span></p></td></tr></tbody></table><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">以及：</span></p><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #d9d9d9; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid green .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid green; mso-border-insidev: .5pt solid green" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>CMultiDocTemplate* pDocTemplate;</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>pDocTemplate = new CMultiDocTemplate(</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>IDR_MISTYPE,</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>RUNTIME_CLASS(CMISDoc),</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>RUNTIME_CLASS(CChildFrame), // custom MDI child frame</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>RUNTIME_CLASS(CMISView));</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>AddDocTemplate(pDocTemplate);*/</span></p></td></tr><tr style="mso-yfti-irow: 1"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt; mso-border-top-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center"><span style="COLOR: red; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">改为</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：（注意将</span><span lang="EN-US" twffan="done">CMultiDocTemplate*</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">去掉，否则你是新建了一个</span><span lang="EN-US" twffan="done">CMultiDocTemplate*</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">的对象）</span></p></td></tr><tr style="mso-yfti-irow: 2; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #ece9d8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt; mso-border-top-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span lang="EN-US" twffan="done">m_pDocTemplate1 = new CMultiDocTemplate(</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>IDR_MISTYPE,</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>RUNTIME_CLASS(CMISDoc),</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>RUNTIME_CLASS(CChildFrame), // custom MDI child frame</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>RUNTIME_CLASS(CMISView));</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span lang="EN-US" twffan="done">AddDocTemplate(m_pDocTemplate1);</span></p></td></tr></tbody></table><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="BACKGROUND: #d9d9d9; COLOR: red; FONT-FAMILY: Arial" twffan="done">Step 5</span></b><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：在</span><span lang="EN-US" twffan="done">MainFrm.h</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">中添加两个文档类变量记录这里的两个不同的</span><span lang="EN-US" twffan="done">Document</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">，为简单起见就声明为</span><span lang="EN-US" twffan="done">public</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：</span></p><div align="center" twffan="done"><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #d9d9d9; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid green .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid green; mso-border-insidev: .5pt solid green" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 257.4pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" valign="top" width="343"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done">public</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">：</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt; mso-char-indent-count: 2.0"><span lang="EN-US" twffan="done">CMISDoc* m_pDoc1;</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>CNewDoc* m_pDoc2</span></p></td></tr></tbody></table></div><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done"><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">注意：在</span><b style="mso-bidi-font-weight: normal"><span lang="EN-US" style="FONT-SIZE: 10.5pt; COLOR: blue; FONT-FAMILY: Arial; mso-fareast-font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">CMainFrame</span><span style="FONT-SIZE: 10.5pt; COLOR: blue; FONT-FAMILY: 宋体; mso-hansi-font-family: Arial; mso-ascii-font-family: Arial; mso-bidi-font-family: Arial; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">构造函数</span></b><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">中将上面两个变量置为</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">NULL</span><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">（否则：））。</span>并响应</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">IDR_MAINFRAME</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">的两个菜单项目“功能</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">1</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">”和“功能</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">2</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-bidi-font-size: 10.5pt" twffan="done">”消息，在各自的响应菜单中分别添加响应函数：</span><span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-size: 10.5pt" twffan="done"><o:p></o:p></span></p><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #d9d9d9; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid green .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid green; mso-border-insidev: .5pt solid green" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>// TODO: Add your command handler code here</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>if (m_pDoc1 != NULL)<span style="mso-spacerun: yes" twffan="done">   </span>//</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">已经打开则激活</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>{</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>POSITION pos;</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>pos =m_pDoc1-&gt;GetFirstViewPosition();</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>CView* pView = m_pDoc1-&gt;GetNextView(pos);</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>pView-&gt;GetParentFrame()-&gt;ActivateFrame();</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>}</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>else</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>{</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>CMISApp* pApp = (CMISApp*)AfxGetApp();</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>m_pDoc1 = (CMISDoc*)(pApp-&gt;m_pDocTemplate1-&gt;OpenDocumentFile(NULL));</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>}</span></p></td></tr></tbody></table><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">和：</span></p><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BACKGROUND: #e0e0e0; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid green .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid green; mso-border-insidev: .5pt solid green" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: green 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: green 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: green 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: green 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid green .5pt" valign="top" width="568"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>// TODO: Add your command handler code here</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>if (m_pDoc2 != NULL)</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>{</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>POSITION pos;</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>pos =m_pDoc2-&gt;GetFirstViewPosition();</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>CView* pView = m_pDoc2-&gt;GetNextView(pos);</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>pView-&gt;GetParentFrame()-&gt;ActivateFrame();</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>}</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>else</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>{</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>CMISApp* pApp = (CMISApp*)AfxGetApp();</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 2" twffan="done">              </span>m_pDoc2 = (CNewDoc*)(pApp-&gt;m_pDocTemplate2-&gt;OpenDocumentFile(NULL));</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span>}</span></p></td></tr></tbody></table><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><o:p> </o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US" twffan="done"><span style="mso-tab-count: 1" twffan="done">       </span></span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">至此就完成了整个工作，需要说明的是：</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'" twffan="done"><span style="mso-list: Ignore" twffan="done">1）<span style="FONT: 7pt 'Times New Roman'" twffan="done">  </span></span></span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">实现中由于使用到相关的类，因此在必要的地方要</span><span lang="EN-US" twffan="done">include</span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">相关的头文件，这里省略（编译有错误的时候添加就是了：））；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'" twffan="done"><span style="mso-list: Ignore" twffan="done">2）<span style="FONT: 7pt 'Times New Roman'" twffan="done">  </span></span></span><span style="FONT-FAMILY: 宋体; mso-hansi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'" twffan="done">这里给出的是一个示例代码，实际开发中可以通过参考实现获得自己想要实现的具体应用情况（例如视图类的不同、数量不同，更重要的还有业务逻辑的不同实现等）；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 39pt; TEXT-INDENT: -18pt; mso-list: l0 level1 lfo1; tab-stops: list 39.0pt"><span lang="EN-US" style="mso-fareast-font-family: 'Times New Roman'" twffan="done"><span style="mso-list: Ignore" twffan="done"> </span></span></p><img src ="http://www.cppblog.com/ivenher/aggbug/20746.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-03-28 09:32 <a href="http://www.cppblog.com/ivenher/articles/20746.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入分析MFC文档视图结构（转）</title><link>http://www.cppblog.com/ivenher/articles/20707.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Tue, 27 Mar 2007 07:32:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/20707.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/20707.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/20707.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/20707.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/20707.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 文档视图结构（				Document/View Architecture				）是				MFC				的精髓，也是				Observer				模式的具体实现框架之一，				Document/View Architecture				通过将数据和其表示分开，提供了很好的数据层次和表现层次的解耦。然而，虽然我们使用				MFC AppWizard	...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/20707.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/20707.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-03-27 15:32 <a href="http://www.cppblog.com/ivenher/articles/20707.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SetTimer的使用问题 </title><link>http://www.cppblog.com/ivenher/articles/19969.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 16 Mar 2007 08:54:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/19969.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/19969.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/19969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/19969.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/19969.html</trackback:ping><description><![CDATA[
		<p>etTimer函数用于创建一个计时器，KillTimer函数用于销毁一个计时器。计时器属于系统资源，使用完应及时销毁。</p>
		<p>　</p>
		<p>　　<strong><font color="#003399">SetTimer</font></strong>的函数原型如下：<br /><font color="#003366">UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc ) ;</font><br />　　其中<br />　　hWnd是和timer关联的窗口句柄，此窗口必须为调用SetTimer的线程所有；如果hWnd为NULL，没有窗口和timer相关联并且nIDEvent参数被忽略 <br />　　nIDEvent是timer的标识，为非零值；如果hWnd为NULL则被忽略；如果hWnd非NULL而且与timer相关联的窗口已经存在一个为此标识的timer，则此次SetTimer调用将用新的timer代替原来的timer。timer标识和窗口相关，两个不同的窗口可以拥有nIDEvent相同的tiemr <br />　　uElapse是以毫秒指定的计时间隔值，范围为1毫秒到4,294,967,295毫秒（将近50天），这个值指示Windows每隔多久时间给程序发送WM_TIMER消息。 <br />　　lpTimerFunc是一个回调函数的指针，俗称TimerFunc；如果lpTimerFunc为NULL，系统将向应用程序队列发送WM_TIMER消息；如果lpTimerFunc指定了一个值，DefWindowProc将在处理WM_TIMER消息时调用这个lpTimerFunc所指向的回调函数，因此即使使用TimerProc代替处理WM_TIMER也需要向窗口分发消息。 <br /></p>
		<p>　　关于SetTimer的返回值：如果hWnd为NULL，返回值为新建立的timer的ID，如果hWnd非NULL，返回一个非0整数，如果SetTimer调用失败则返回0 <br /></p>
		<p>　　<strong><font color="#003399">KillTimer</font></strong>的函数原型为：<font color="#003366">BOOL KillTimer( HWND hWnd, UINT_PTR uIDEvent ) ;</font> 参数意义同SetTimer。 <br />　　关于KillTimer对消息队列中剩余未处理的WM_TIMER消息的影响，MSDN和Programming Windows上的说法完全相反。MSDN的说法很干脆：<font color="#336600">The KillTimer function does not remove WM_TIMER messages already posted to the message queue.</font> 而petzold则说 <font color="#336600">The KillTimer call purges the message queue of any pending WM_TIMER messages. Your program will never receive a stray WM_TIMER message following a KillTimer call.</font><font color="#339900"></font>(KillTimer消除消息队列中任何未处理的WM_TIMER消息，调用KillTimer后你的程序永远不会收到一条“漂泊游荡”的WM_TIMER消息) </p>
		<p>  
</p>
		<table cellspacing="0" cellpadding="2" width="100%" bgcolor="#003399" border="0">
				<tbody>
						<tr>
								<td>
										<font color="#ffffff">
												<strong>关于WM_TIMER消息</strong>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<strong>
				</strong>　　wParam为计时器的ID；如果需要设定多个计时器，那么对每个计时器都使用不同的计时器ID。wParam的值将随传递到窗口过程中的WM_TIMER消息的不同而不同。<br />　　lParam为指向TimerProc的指针，如果调用SetTimer时没有指定TimerProc(参数值为NULL)，则lParam为0(即NULL)。 <br />　　可以通过在窗口过程中提供一个WM_TIMER case处理这个消息，或者，默认窗口过程会调用SetTimer中指定的TimerProc来处理WM_TIMER消息</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="2" width="100%" bgcolor="#003498" border="0">
				<tbody>
						<tr>
								<td>
										<strong>
												<font color="#ffffff">使用计时器的三种方法</font>
										</strong>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　如果在程序的整个执行过程中使用计时器，一般在处理WM_CREATE消息时或WinMain中消息循环前调用SetTimer,在处理WM_DESTROY消息时或在WinMain中消息循环后return前调用KillTimer。根据SetTimer中的参数不同，有三种方法使用计时器。</p>
		<p>　　方法一：<font color="#003366">调用SetTimer时<font color="#ff3333">指定窗口句柄</font>hWnd，nIDEvent中<font color="#ff3333">指定计时器ID</font>，将<font color="#ff3333">lpTimerFunc置NULL</font>从而不使用TimerProc；<font color="#ff3333">在窗口过程中处理WM_TIMER消息</font>。</font>调用KillTimer时，使用SetTimer中指定的hWnd和id。最好使用#define定义timer的id，例如：</p>
		<p>
		</p>
		<table cellpadding="2" width="90%" align="center" bgcolor="#666666" border="0">
				<tbody>
						<tr bgcolor="#cccccc">
								<td>
										<font color="#003366">#define ID_TIMER 1 <br />SetTimer(hWnd,ID_TIMER,1000,NULL) ;<br />KillTimer(hWnd,ID_TIMER) ;</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　方法二：<font color="#003366">调用SetTimer时<font color="#ff3333">指定窗口句柄</font>hWnd，nIDEvent中<font color="#ff3333">指定计时器ID</font>，<font color="#ff3333">lpTimerFunc参数不为NULL</font>而指定为TimerProc函数的指针。</font>这种方法<font color="#ff3333">使用TimerProc函数(名字可自定)处理WM_TIMER消息</font>：</p>
		<p>
		</p>
		<table cellpadding="2" width="90%" align="center" bgcolor="#666666" border="0">
				<tbody>
						<tr bgcolor="#cccccc">
								<td>
										<font color="#003366">VOID CALLBACK TimerProc ( HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)<br />{<br />　//处理WM_TIMER讯息 <br />}</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　　TimerProc的参数hwnd是在调用SetTimer时指定的窗口句柄。Windows只把WM_TIMER消息送给TimerProc，因此消息参数总是等于WM_TIMER。iTimerID值是计时器ID，dwTimer值是与从GetTickCount函数的返回值相容的值。这是自Windows启动后所经过的毫秒数。 使用这种方法时，相关函数调用的形式为：</p>
		<p>
		</p>
		<table cellpadding="2" width="90%" align="center" bgcolor="#666666" border="0">
				<tbody>
						<tr bgcolor="#cccccc">
								<td>
										<font color="#003366">SetTimer(hWnd,ID_TIMER,1000,TimerProc) ;<br />KillTimer(hWnd,ID_TIMER) ;</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　方法三：<font color="#003366">调用SetTimer时<font color="#ff3333">不指定窗口句柄(为NULL)</font>，<font color="#ff3333">iTimerID参数自然被忽略</font>，<font color="#ff3333">lpTimerFunc不为NULL</font>而指定为TimerProc的指针。</font>正如上面SetTimer的讨论中所说的，此时SetTimer的返回值正是新建立的计时器的ID，需将这个ID保存以供KillTimer销毁计时器时所用。当然，KillTimer的hWnd参数也置为NULL。这种方法<font color="#ff3333">同样用TimerProc处理WM_TIMER消息</font>。</p>
		<p>
		</p>
		<table cellpadding="2" width="90%" align="center" bgcolor="#666666" border="0">
				<tbody>
						<tr bgcolor="#cccccc">
								<td>
										<font color="#003366">UINT_PTR iTimerID ; <br />iTimerID = SetTimer(NULL,0,1000,TimerProc) ;<br />KillTimer(NULL,iTimerID) ;</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　使用这种方法的好处是不必自己指定计时器ID,这样就不必担心用错ID。</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="2" width="100%" bgcolor="#b0a8d8" border="0">
				<tbody>
						<tr bgcolor="#003399">
								<td>
										<font color="#ffffff">
												<strong>使用多个计时器</strong>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　使用多个计时器只要在建立计时器时指定不同的ID。比如用上面所述方法一时的情况：</p>
		<p>
		</p>
		<table cellpadding="2" width="90%" align="center" bgcolor="#666666" border="0">
				<tbody>
						<tr bgcolor="#cccccc">
								<td>
										<font color="#003366">#define TIMER_SEC 1<br />#define TIMER_MIN 2</font>
										<br />然后使用两个SetTimer来设定两个计时器：<br /><font color="#003366">SetTimer (hwnd, TIMER_SEC, 1000, NULL) ;<br />SetTimer (hwnd, TIMER_MIN, 60000, NULL) ; </font><br />WM_TIMER的处理如下所示：<br /><font color="#003366">case WM_TIMER:<br />　switch (wParam)<br />　{<br />　　case TIMER_SEC:<br />　　　//每秒一次的处理 <br />　　　break ;<br />　　case TIMER_MIN:<br />　　　//每分钟一次的处理<br />　　　break ;<br />　}<br />　return 0 ;</font></td>
						</tr>
				</tbody>
		</table>
		<p> </p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="2" width="100%" bgcolor="#003498" border="0">
				<tbody>
						<tr>
								<td>
										<font color="#ffffff">
												<strong>改变计时器的时间间隔</strong>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　如果想将一个已经存在的计时器设定为不同的时间间隔，可以简单地用不同的时间值再次调用SetTimer。</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="2" width="100%" bgcolor="#003498" border="0">
				<tbody>
						<tr>
								<td>
										<font color="#ffffff">
												<strong>计时器精确吗？</strong>
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>　　计时器并不精确。有两个原因：</p>
		<p>　　原因一：Windows计时器是硬件和ROM BIOS架构下之计时器一种相对简单的扩充。回到Windows以前的MS-DOS程序写作环境下，应用程式能够通过拦截者称为timer tick的BIOS中断来实现时钟或计时器。一些为MS-DOS编写的程序自己拦截这个硬件中断以实现时钟和计时器。这些中断每54.915毫秒产生一次，或者大约每秒18.2次。这是原始的IBM PC的微处理器频率值4.772720 MHz被218所除而得出的结果。在Windows 98中，计时器与其下的PC计时器一样具有55毫秒的解析度。在Microsoft Windows NT中，计时器的解析度为10毫秒。Windows应用程式不能以高于这些解析度的频率（在Windows 98下，每秒18.2次，在Windows NT下，每秒大约100次）接收WM_TIMER消息。在SetTimer中指定的时间间隔总是截尾后tick数的整数倍。例如，1000毫秒的间隔除以54.925毫秒，得到18.207个tick，截尾后是18个tick，它实际上是989毫秒。对每个小于55毫秒的间隔，每个tick都会产生一个WM_TIMER消息。 <br />　　可见，计时器并不能严格按照指定的时间间隔发送WM_TIMER消息，它总要相差那么几毫秒。</p>
		<p>　　即使忽略这几个毫秒的差别，计时器仍然不精确。请看原因二：<br />　　WM_TIMER消息放在正常的消息队列之中，和其他消息排列在一起，因此，如果在SetTimer中指定间隔为1000毫秒，那么不能保证程序每1000毫秒或者989毫秒就会收到一个WM_TIMER消息。如果其他程序的执行事件超过一秒，在此期间内，您的程式将收不到任何WM_TIMER讯息。事实上， Windows对WM_TIMER消息的处理非常类似于对WM_PAINT消息的处理，这两个消息都是低优先级的，程序只有在消息队列中没有其他消息时才接收它们。<br />　　WM_TIMER还在另一方面和WM_PAINT相似：Windows不能持续向消息队列中放入多个WM_TIMER讯息，而是将多余的WM_TIMER消息组合成一个消息。因此，应用程序不会一次收到多个这样的消息，尽管可能在短时间内得到两个WM_TIMER消息。应用程序不能确定这种处理方式所导致的WM_TIMER消息「遗漏」的数目。<br />　　可见，WM_TIMER消息并不能及时被应用程序所处理，WM_TIMER在消息队列中的延误可能就不能用毫秒来计算了。</p>
		<p>　　由以上两点，你不能通过在处理WM_TIMER时一秒一秒计数的方法来计时。如果要实现一个时钟程序，可以使用系统的时间函数如GetLocalTime ，而在时钟程序中，计时器的作用是定时调用GetLocalTime获得新的时间并刷新时钟画面，当然这个刷新的间隔要等于或小于1秒。</p>
		<p> </p>
<img src ="http://www.cppblog.com/ivenher/aggbug/19969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-03-16 16:54 <a href="http://www.cppblog.com/ivenher/articles/19969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入getmessage和peekmessage</title><link>http://www.cppblog.com/ivenher/articles/12473.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 14 Sep 2006 10:18:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12473.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12473.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12473.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12473.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: bob gunderson																		msdn						技术组																		作于						:1992						年						11						月						11						日																																 					...&nbsp;&nbsp;<a href='http://www.cppblog.com/ivenher/articles/12473.html'>阅读全文</a><img src ="http://www.cppblog.com/ivenher/aggbug/12473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-14 18:18 <a href="http://www.cppblog.com/ivenher/articles/12473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CArchive原理 </title><link>http://www.cppblog.com/ivenher/articles/12459.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 14 Sep 2006 07:17:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12459.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12459.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12459.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12459.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12459.html</trackback:ping><description><![CDATA[
		<div class="postsub" twffan="done">
				<p>
						<strong>
								<img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" />
								<a name="A1">
								</a>一.概述 </strong>
				</p>CArchive使用了缓冲区，即一段内存空间作为临时数据存储地，对CArchive的读写都先依次排列到此缓冲区，当缓冲区满或用户要求时，将此段整理后的数据读写到指定的存储煤质。 <br />当建立CArchive对象时，应指定其模式是用于缓冲区读，还是用于缓冲区写。 <br />可以这样理解，CArchive对象相当于铁路的货运练调度站，零散的货物被收集，当总量到达火车运量的时候，由火车装运走。 <br />当接到火车的货物时，则货物由被分散到各自的货主。与货运不同的是，交货、取货是按时间循序执行的，而不是凭票据。因此必须保证送货的和取货的货主按同样的循序去存或取。 <br />对于大型的货物，则是拆散成火车单位，运走，取货时，依次取各部分，组装成原物。 
<p></p><p><strong><img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" /><a id="A2" name="A2"></a>二.内部数据</strong><br />缓冲区指针 BYTE* m_lpBufStart,指向缓冲区，这个缓冲区有可能是底层CFile(如派生类CMemFile)对象提供的，但一般是CArchive自己建立的。 <br />缓冲区尾部指针 BYTE* m_lpBufMax; <br />缓冲区当前位置指针 BYTE* m_lpBufCur; <br />初始化时，如果是读模式,当前位置在尾部，如果是写模式，当前位置在头部: </p><pre>m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;</pre><strong><img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" /><a id="A3" name="A3"></a>三.基本数据读写 </strong><p>对于基本的数据类型，例如字节、双字等，可以直接使用"&gt;&gt;"、"&lt;&lt;"符号进行读出、写入。 </p><pre>//操作符定义捕:
	
//插入操作
CArchive&amp; operator&lt;&lt;(BYTE by);
CArchive&amp; operator&lt;&lt;(WORD w);
CArchive&amp; operator&lt;&lt;(LONG l);
CArchive&amp; operator&lt;&lt;(DWORD dw);
CArchive&amp; operator&lt;&lt;(float f);
CArchive&amp; operator&lt;&lt;(double d);
CArchive&amp; operator&lt;&lt;(int i);
CArchive&amp; operator&lt;&lt;(short w);
CArchive&amp; operator&lt;&lt;(char ch);
CArchive&amp; operator&lt;&lt;(unsigned u);

//提取操作
CArchive&amp; operator&gt;&gt;(BYTE&amp; by);
CArchive&amp; operator&gt;&gt;(WORD&amp; w);
CArchive&amp; operator&gt;&gt;(DWORD&amp; dw);
CArchive&amp; operator&gt;&gt;(LONG&amp; l);
CArchive&amp; operator&gt;&gt;(float&amp; f);
CArchive&amp; operator&gt;&gt;(double&amp; d);

CArchive&amp; operator&gt;&gt;(int&amp; i);
CArchive&amp; operator&gt;&gt;(short&amp; w);
CArchive&amp; operator&gt;&gt;(char&amp; ch);
CArchive&amp; operator&gt;&gt;(unsigned&amp; u);</pre>下面以双字为例，分析原码 
<p><strong>双字的插入(写)</strong></p><pre>CArchive&amp; CArchive::operator&lt;&lt;(DWORD dw)
{
	if (m_lpBufCur + sizeof(DWORD) &gt; m_lpBufMax) //缓冲区空间不够
		Flush();  //缓冲区内容提交到实际存储煤质。

	if (!(m_nMode &amp; bNoByteSwap))
		_AfxByteSwap(dw, m_lpBufCur);  //处理字节顺序
	else
		*(DWORD*)m_lpBufCur = dw;      //添入缓冲区

	m_lpBufCur += sizeof(DWORD); 	   //移动当前指针
	return *this;
}
</pre><strong>双字的提取(读)</strong><pre>CArchive&amp; CArchive::operator&gt;&gt;(DWORD&amp; dw)
{
	if (m_lpBufCur + sizeof(DWORD) &gt; m_lpBufMax) //缓冲区要读完了
		FillBuffer(sizeof(DWORD) - (UINT)(m_lpBufMax - m_lpBufCur));  //重新读入内容到缓冲区

	dw = *(DWORD*)m_lpBufCur;		//读取双字
	m_lpBufCur += sizeof(DWORD);	//移动当前位置指针

	if (!(m_nMode &amp; bNoByteSwap))
		_AfxByteSwap(dw, (BYTE*)&amp;dw);  //处理字节顺序
	return *this;
}
</pre><strong><img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" /><a id="A4" name="A4"></a>四.缓冲区的更新</strong><br /><br />以上操作中，当缓冲区将插入满或缓冲区将提取空时，都将对缓冲区进行更新处理。<br /><br />缓冲区将插入满时调用Flush(); <pre>void CArchive::Flush()
{
	ASSERT_VALID(m_pFile);
	ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
	ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
	ASSERT(m_lpBufStart == NULL ||
		AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
	ASSERT(m_lpBufCur == NULL ||
		AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));

	if (IsLoading())
	{
		// unget the characters in the buffer, seek back unused amount
		if (m_lpBufMax != m_lpBufCur)
			m_pFile-&gt; Seek(-(m_lpBufMax - m_lpBufCur), CFile::current);
		m_lpBufCur = m_lpBufMax;    // 指向尾
	}
	else   //写模式
	{
		if (!m_bDirectBuffer)
		{
			// 内容写入到文件
			if (m_lpBufCur != m_lpBufStart)
				m_pFile-&gt; Write(m_lpBufStart, m_lpBufCur - m_lpBufStart);
		}
		else
		{
			//如果是直接针对内存区域的的(例如CMemFile中) (只需移动相关指针，指向新的一块内存)
			if (m_lpBufCur != m_lpBufStart)
				m_pFile-&gt; GetBufferPtr(CFile::bufferCommit, m_lpBufCur - m_lpBufStart);
			// get next buffer
			VERIFY(m_pFile-&gt; GetBufferPtr(CFile::bufferWrite, m_nBufSize,
				(void**)&amp;m_lpBufStart, (void**)&amp;m_lpBufMax) == (UINT)m_nBufSize);
			ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
		}
		m_lpBufCur = m_lpBufStart; //指向缓冲区首
	}
}</pre>缓冲区将提取空,会调用FillBuffer。 nBytesNeeded为当前剩余部分上尚有用的字节<pre>void CArchive::FillBuffer(UINT nBytesNeeded)
{
	ASSERT_VALID(m_pFile);
	ASSERT(IsLoading());
	ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
	ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
	ASSERT(nBytesNeeded &gt; 0);
	ASSERT(nBytesNeeded &lt;= (UINT)m_nBufSize);
	ASSERT(m_lpBufStart == NULL ||
		AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
	ASSERT(m_lpBufCur == NULL ||
		AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));

	UINT nUnused = m_lpBufMax - m_lpBufCur;
	ULONG nTotalNeeded = ((ULONG)nBytesNeeded) + nUnused;

	// 从文件中读取
	if (!m_bDirectBuffer)
	{
		ASSERT(m_lpBufCur != NULL);
		ASSERT(m_lpBufStart != NULL);
		ASSERT(m_lpBufMax != NULL);

		if (m_lpBufCur &gt; m_lpBufStart)
		{
			//保留剩余的尚未处理的部分，将它们移动到头
			if ((int)nUnused &gt; 0)
			{
				memmove(m_lpBufStart, m_lpBufCur, nUnused);
				m_lpBufCur = m_lpBufStart;
				m_lpBufMax = m_lpBufStart + nUnused;
			}

			// read to satisfy nBytesNeeded or nLeft if possible
			UINT nRead = nUnused;
			UINT nLeft = m_nBufSize-nUnused;
			UINT nBytes;
			BYTE* lpTemp = m_lpBufStart + nUnused;
			do
			{
				nBytes = m_pFile-&gt; Read(lpTemp, nLeft);
				lpTemp = lpTemp + nBytes;
				nRead += nBytes;
				nLeft -= nBytes;
			}
			while (nBytes &gt; 0 &amp;&amp; nLeft &gt; 0 &amp;&amp; nRead &lt; nBytesNeeded);

			m_lpBufCur = m_lpBufStart;
			m_lpBufMax = m_lpBufStart + nRead;
		}
	}
	else
	{
		// 如果是针对内存区域(CMemFile),移动相关指针，指向新的一块内存
		if (nUnused != 0)
			m_pFile-&gt; Seek(-(LONG)nUnused, CFile::current);
		UINT nActual = m_pFile-&gt; GetBufferPtr(CFile::bufferRead, m_nBufSize,
			(void**)&amp;m_lpBufStart, (void**)&amp;m_lpBufMax);
		ASSERT(nActual == (UINT)(m_lpBufMax - m_lpBufStart));
		m_lpBufCur = m_lpBufStart;
	}

	// not enough data to fill request?
	if ((ULONG)(m_lpBufMax - m_lpBufCur) &lt; nTotalNeeded)
		AfxThrowArchiveException(CArchiveException::endOfFile);
}
</pre><strong><img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" /><a id="A5" name="A5"></a>五.指定长度数据段落的读写</strong><br /><br />以下分析 <br />UINT Read(void* lpBuf, UINT nMax); 读取长度为nMax的数据 <br />void Write(const void* lpBuf, UINT nMax); 写入指定长度nMax的数据 <br />对于大段数据的读写，先使用当前缓冲区中的内容或空间读取或写入，若这些空间够用了，则结束。 <br />否则，从剩余的数据中找出最大的缓冲区整数倍大小的一块数据，直接读写到存储煤质(不反复使用缓冲区)。 <br />剩余的余数部分，再使用缓冲区读写。 <br />(说明:缓冲区读写的主要目的是将零散的数据以缓冲区大小为尺度来处理。对于大型数据，其中间的部分，不是零散的数据，使用缓冲区已经没有意思，故直接读写) 
<p><strong>①读取 </strong></p><pre>UINT CArchive::Read(void* lpBuf, UINT nMax)
{
	ASSERT_VALID(m_pFile);
	if (nMax == 0)
		return 0;

	UINT nMaxTemp = nMax;  //还需要读入的长度，读入一部分，就减相应数值，直到此数值变为零
	
	//处理当前缓冲区中剩余部分。
	//如果要求读入字节小于缓冲区中剩余部分,则第一部分为要求读入的字节数，
	//否则读入全部剩余部分	
	UINT nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));   
	memcpy(lpBuf, m_lpBufCur, nTemp);
	m_lpBufCur += nTemp;
	lpBuf = (BYTE*)lpBuf + nTemp; //移动读出内容所在区域的指针
	nMaxTemp -= nTemp;

	//当前缓冲区中剩余部分不够要求读入的长度。
	//还有字节需要读，则需要根据需要执行若干次填充缓冲区，读出，直到读出指定字节。
	if (nMaxTemp != 0)  
	{
		//计算出去除尾数部分的字节大小(整数个缓冲区大小) 
		//对于这些部分，字节从文件对象中读出，放到输出缓冲区
		nTemp = nMaxTemp - (nMaxTemp % m_nBufSize);  
		UINT nRead = 0;

		UINT nLeft = nTemp;
		UINT nBytes;
		do
		{
			nBytes = m_pFile-&gt; Read(lpBuf, nLeft); //要求读入此整数缓冲区部分大小
			lpBuf = (BYTE*)lpBuf + nBytes;
			nRead += nBytes;
			nLeft -= nBytes;
		}
		while ((nBytes &gt; 0) &amp;&amp; (nLeft &gt; 0)); 知道读入了预定大小，或到达文件尾

		nMaxTemp -= nRead;

		if (nRead == nTemp) //读入的字节等于读入的整数倍部分  该读最后的余数部分了
		{
			// 建立装有此最后余数部分的内容的CArchive的工作缓冲区。
			if (!m_bDirectBuffer)
			{
				UINT nLeft = max(nMaxTemp, (UINT)m_nBufSize);
				UINT nBytes;
				BYTE* lpTemp = m_lpBufStart;
				nRead = 0;
				do
				{
					nBytes = m_pFile-&gt; Read(lpTemp, nLeft);  //从文件中读入到CArchive缓冲区
					lpTemp = lpTemp + nBytes;
					nRead += nBytes;
					nLeft -= nBytes;
				}
				while ((nBytes &gt; 0) &amp;&amp; (nLeft &gt; 0) &amp;&amp; nRead &lt; nMaxTemp);

				m_lpBufCur = m_lpBufStart;
				m_lpBufMax = m_lpBufStart + nRead;
			}
			else
			{
				nRead = m_pFile-&gt; GetBufferPtr(CFile::bufferRead, m_nBufSize,
					(void**)&amp;m_lpBufStart, (void**)&amp;m_lpBufMax);
				ASSERT(nRead == (UINT)(m_lpBufMax - m_lpBufStart));
				m_lpBufCur = m_lpBufStart;
			}

			//读出此剩余部分到输出
			nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
			memcpy(lpBuf, m_lpBufCur, nTemp);
			m_lpBufCur += nTemp;
			nMaxTemp -= nTemp;
		}
		
	}
	return nMax - nMaxTemp;
}
</pre><strong>②保存,写入</strong><pre>void CArchive::Write(const void* lpBuf, UINT nMax)
{
	if (nMax == 0)
		return;
	
	//读入可能的部分到缓冲区当前的剩余部分	
	UINT nTemp = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur));
	memcpy(m_lpBufCur, lpBuf, nTemp);
	m_lpBufCur += nTemp;
	lpBuf = (BYTE*)lpBuf + nTemp;
	nMax -= nTemp;

	if (nMax &gt; 0)  //还有未写入的部分
	{
		Flush();    //将当前缓冲区写入到存储煤质

		//计算出整数倍缓冲区大小的字节数
		nTemp = nMax - (nMax % m_nBufSize);
		m_pFile-&gt; Write(lpBuf, nTemp);  //直接写到文件
		lpBuf = (BYTE*)lpBuf + nTemp;
		nMax -= nTemp;


		//剩余部分添加到缓冲区
		if (m_bDirectBuffer)
		{
			// sync up direct mode buffer to new file position
			VERIFY(m_pFile-&gt; GetBufferPtr(CFile::bufferWrite, m_nBufSize,
				(void**)&amp;m_lpBufStart, (void**)&amp;m_lpBufMax) == (UINT)m_nBufSize);
			ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
			m_lpBufCur = m_lpBufStart;
		}

		// copy remaining to active buffer
		ASSERT(nMax &lt; (UINT)m_nBufSize);
		ASSERT(m_lpBufCur == m_lpBufStart);
		memcpy(m_lpBufCur, lpBuf, nMax);
		m_lpBufCur += nMax;
	}
}
</pre><strong><img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" /><a id="A6" name="A6"></a>六.字符串的读写<br /><br />①CArchive提供的WriteString和ReadString </strong><br /><br /><strong>字符串写</strong><pre>void CArchive::WriteString(LPCTSTR lpsz)
{
	ASSERT(AfxIsValidString(lpsz));
	Write(lpsz, lstrlen(lpsz) * sizeof(TCHAR));  //调用Write，将字符串对应的一段数据写入
}
</pre><strong>字符串读(读取一行字符串)</strong><pre>LPTSTR CArchive::ReadString(LPTSTR lpsz, UINT nMax)
{
	// if nMax is negative (such a large number doesn''t make sense given today''s
	// 2gb address space), then assume it to mean "keep the newline".
	int nStop = (int)nMax &lt; 0 ? -(int)nMax : (int)nMax;
	ASSERT(AfxIsValidAddress(lpsz, (nStop+1) * sizeof(TCHAR)));

	_TUCHAR ch;
	int nRead = 0;

	TRY
	{
		while (nRead &lt; nStop)
		{
			*this &gt;&gt; ch;  //读出一个字节

			// stop and end-of-line (trailing ''\n'' is ignored)  遇换行—回车
			if (ch == ''\n'' || ch == ''\r'')
			{
				if (ch == ''\r'')
					*this &gt;&gt; ch;
				// store the newline when called with negative nMax
				if ((int)nMax != nStop)
					lpsz[nRead++] = ch;
				break;
			}
			lpsz[nRead++] = ch;
		}
	}
	CATCH(CArchiveException, e)
	{
		if (e-&gt; m_cause == CArchiveException::endOfFile)
		{
			DELETE_EXCEPTION(e);
			if (nRead == 0)
				return NULL;
		}
		else
		{
			THROW_LAST();
		}
	}
	END_CATCH

	lpsz[nRead] = ''\0'';
	return lpsz;
}
</pre><strong>ReadString到CString对象,可以多行字符</strong><pre>BOOL CArchive::ReadString(CString&amp; rString)
{
	rString = &amp;afxChNil;    // empty string without deallocating
	const int nMaxSize = 128;
	LPTSTR lpsz = rString.GetBuffer(nMaxSize);
	LPTSTR lpszResult;
	int nLen;
	for (;;)
	{
		lpszResult = ReadString(lpsz, (UINT)-nMaxSize); // store the newline
		rString.ReleaseBuffer();

		// if string is read completely or EOF
		if (lpszResult == NULL ||
			(nLen = lstrlen(lpsz)) &lt; nMaxSize ||
			lpsz[nLen-1] == ''\n'')
		{
			break;
		}

		nLen = rString.GetLength();
		lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
	}

	// remove ''\n'' from end of string if present
	lpsz = rString.GetBuffer(0);
	nLen = rString.GetLength();
	if (nLen != 0 &amp;&amp; lpsz[nLen-1] == ''\n'')
		rString.GetBufferSetLength(nLen-1);

	return lpszResult != NULL;
}
</pre><strong>②使用CString对象的"&lt;&lt;"与"&gt;&gt;"符读写字符串</strong><p>CString定义了输入输出符,可以象基本类型的数据一样使用CArchive 的操作符定义 </p><pre>friend CArchive&amp; AFXAPI operator&lt;&lt;(CArchive&amp; ar, const CString&amp; string);
friend CArchive&amp; AFXAPI operator&gt;&gt;(CArchive&amp; ar, CString&amp; string);</pre><pre>// CString serialization code
// String format:
//      UNICODE strings are always prefixed by 0xff, 0xfffe
//      if &lt; 0xff chars: len:BYTE, TCHAR chars
//      if &gt;= 0xff characters: 0xff, len:WORD, TCHAR chars
//      if &gt;= 0xfffe characters: 0xff, 0xffff, len:DWORD, TCHARs

CArchive&amp; AFXAPI operator&lt;&lt;(CArchive&amp; ar, const CString&amp; string)
{
	// special signature to recognize unicode strings
#ifdef _UNICODE
	ar &lt;&lt; (BYTE)0xff;
	ar &lt;&lt; (WORD)0xfffe;
#endif

	if (string.GetData()-&gt; nDataLength &lt; 255)
	{
		ar &lt;&lt; (BYTE)string.GetData()-&gt; nDataLength;
	}
	else if (string.GetData()-&gt; nDataLength &lt; 0xfffe)
	{
		ar &lt;&lt; (BYTE)0xff;
		ar &lt;&lt; (WORD)string.GetData()-&gt; nDataLength;
	}
	else
	{
		ar &lt;&lt; (BYTE)0xff;
		ar &lt;&lt; (WORD)0xffff;
		ar &lt;&lt; (DWORD)string.GetData()-&gt; nDataLength;
	}
	ar.Write(string.m_pchData, string.GetData()-&gt; nDataLength*sizeof(TCHAR));
	return ar;
}

// return string length or -1 if UNICODE string is found in the archive
AFX_STATIC UINT AFXAPI _AfxReadStringLength(CArchive&amp; ar)
{
	DWORD nNewLen;

	// attempt BYTE length first
	BYTE bLen;
	ar &gt;&gt; bLen;

	if (bLen &lt; 0xff)
		return bLen;

	// attempt WORD length
	WORD wLen;
	ar &gt;&gt; wLen;
	if (wLen == 0xfffe)
	{
		// UNICODE string prefix (length will follow)
		return (UINT)-1;
	}
	else if (wLen == 0xffff)
	{
		// read DWORD of length
		ar &gt;&gt; nNewLen;
		return (UINT)nNewLen;
	}
	else
		return wLen;
}

CArchive&amp; AFXAPI operator&gt;&gt;(CArchive&amp; ar, CString&amp; string)
{
#ifdef _UNICODE
	int nConvert = 1;   // if we get ANSI, convert
#else
	int nConvert = 0;   // if we get UNICODE, convert
#endif

	UINT nNewLen = _AfxReadStringLength(ar);
	if (nNewLen == (UINT)-1)
	{
		nConvert = 1 - nConvert;
		nNewLen = _AfxReadStringLength(ar);
		ASSERT(nNewLen != -1);
	}

	// set length of string to new length
	UINT nByteLen = nNewLen;
#ifdef _UNICODE
	string.GetBufferSetLength((int)nNewLen);
	nByteLen += nByteLen * (1 - nConvert);  // bytes to read
#else
	nByteLen += nByteLen * nConvert;    // bytes to read
	if (nNewLen == 0)
		string.GetBufferSetLength(0);
	else
		string.GetBufferSetLength((int)nByteLen+nConvert);
#endif

	// read in the characters
	if (nNewLen != 0)
	{
		ASSERT(nByteLen != 0);

		// read new data
		if (ar.Read(string.m_pchData, nByteLen) != nByteLen)
			AfxThrowArchiveException(CArchiveException::endOfFile);

		// convert the data if as necessary
		if (nConvert != 0)
		{
#ifdef _UNICODE
			CStringData* pOldData = string.GetData();
			LPSTR lpsz = (LPSTR)string.m_pchData;
#else
			CStringData* pOldData = string.GetData();
			LPWSTR lpsz = (LPWSTR)string.m_pchData;
#endif
			lpsz[nNewLen] = ''\0'';    // must be NUL terminated
			string.Init();   // don''t delete the old data
			string = lpsz;   // convert with operator=(LPWCSTR)
			CString::FreeData(pOldData);
		}
	}
	return ar;
}
</pre><strong><img height="16" src="http://www.vckbase.com/document/image/paragraph.gif" width="14" twffan="done" /><a id="A7" name="A7"></a>七</strong><strong>.CObject派生对象的读写 </strong><p>MFC中多数类都从CObject类派生，CObject类与CArchive类有着良好的合作关系，能实现将对象序列化储存到文件或其他媒介中去，或者读取预先储存的对象，动态建立对象等功能。 </p><p><strong>①CObject定义了针对CArvhive的输入输出操作符,可以向其他基本数据类型一样使用"&lt;&lt;"、"&lt;&lt;"符号</strong></p><pre>CArchive&amp; AFXAPI operator&lt;&lt;(CArchive&amp; ar, const CObject* pOb)
	{ ar.WriteObject(pOb); return ar; }
CArchive&amp; AFXAPI operator&gt;&gt;(CArchive&amp; ar, CObject*&amp; pOb)
	{ pOb = ar.ReadObject(NULL); return ar; }
</pre>当使用这些符号时，实际上执行的是CArchive的WriteObject和ReadObject成员 
<p><strong>②WriteObject与ReadObject</strong></p><p>在WriteObject与ReadObject中先写入或读取运行时类信息(CRuntimeClas)，再调用Serialze(..),按其中的代码读写具体的对象数据。 </p><p>因此，只要在CObject派生类中重载Serilize()函数，写入具体的读写过程，就可以使对象具有存储与创建能力。<br /></p><pre>//将对象写入到缓冲区
void CArchive::WriteObject(const CObject* pOb)
{
	DWORD nObIndex;
	// make sure m_pStoreMap is initialized
	MapObject(NULL);

	if (pOb == NULL)
	{
		// save out null tag to represent NULL pointer
		*this &lt;&lt; wNullTag;
	}
	else if ((nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0)
		// assumes initialized to 0 map
	{
		// save out index of already stored object
		if (nObIndex &lt; wBigObjectTag)
			*this &lt;&lt; (WORD)nObIndex;
		else
		{
			*this &lt;&lt; wBigObjectTag;
			*this &lt;&lt; nObIndex;
		}
	}
	else
	{
		// write class of object first
		CRuntimeClass* pClassRef = pOb-&gt; GetRuntimeClass();
		WriteClass(pClassRef);  //写入运行类信息

		// enter in stored object table, checking for overflow
		CheckCount();
		(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;

		// 调用CObject的Serialize成员，按其中的代码写入类中数据。
		((CObject*)pOb)-&gt; Serialize(*this);
	}
}

</pre><pre>CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
{

	// attempt to load next stream as CRuntimeClass
	UINT nSchema;
	DWORD obTag;
	//先读入运行时类信息
	CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &amp;nSchema, &amp;obTag);

	// check to see if tag to already loaded object
	CObject* pOb;
	if (pClassRef == NULL)
	{
		if (obTag &gt; (DWORD)m_pLoadArray-&gt; GetUpperBound())
		{
			// tag is too large for the number of objects read so far
			AfxThrowArchiveException(CArchiveException::badIndex,
				m_strFileName);
		}

		pOb = (CObject*)m_pLoadArray-&gt; GetAt(obTag);
		if (pOb != NULL &amp;&amp; pClassRefRequested != NULL &amp;&amp;
			 !pOb-&gt; IsKindOf(pClassRefRequested))
		{
			// loaded an object but of the wrong class
			AfxThrowArchiveException(CArchiveException::badClass,
				m_strFileName);
		}
	}
	else
	{
		// 建立对象
		pOb = pClassRef-&gt; CreateObject();
		if (pOb == NULL)
			AfxThrowMemoryException();

		// Add to mapping array BEFORE de-serializing
		CheckCount();
		m_pLoadArray-&gt; InsertAt(m_nMapCount++, pOb);

		// Serialize the object with the schema number set in the archive
		UINT nSchemaSave = m_nObjectSchema;
		m_nObjectSchema = nSchema;
		pOb-&gt; Serialize(*this); //调用CObject的Serialize,按其中代码读入对象数据。
		m_nObjectSchema = nSchemaSave;
		ASSERT_VALID(pOb);
	}

	return pOb;
}

</pre><strong>③运行时类信息的读写</strong><p>为了避免众多重复的同类对象写入重复的类信息，CArchive中使用CMap对象储存和检索类信息。<br /></p><pre>void CArchive::WriteClass(const CRuntimeClass* pClassRef)
{
	ASSERT(pClassRef != NULL);
	ASSERT(IsStoring());    // proper direction

	if (pClassRef-&gt; m_wSchema == 0xFFFF)
	{
		TRACE1("Warning: Cannot call WriteClass/WriteObject for %hs.\n",
			pClassRef-&gt; m_lpszClassName);
		AfxThrowNotSupportedException();
	}

	// make sure m_pStoreMap is initialized
	MapObject(NULL);

	// write out class id of pOb, with high bit set to indicate
	// new object follows

	// ASSUME: initialized to 0 map
	DWORD nClassIndex;
	if ((nClassIndex = (DWORD)(*m_pStoreMap)[(void*)pClassRef]) != 0)
	{
		// previously seen class, write out the index tagged by high bit
		if (nClassIndex &lt; wBigObjectTag)
			*this &lt;&lt; (WORD)(wClassTag | nClassIndex);
		else
		{
			*this &lt;&lt; wBigObjectTag;
			*this &lt;&lt; (dwBigClassTag | nClassIndex);
		}
	}
	else
	{
		// store new class
		*this &lt;&lt; wNewClassTag;
		pClassRef-&gt; Store(*this);

		// store new class reference in map, checking for overflow
		CheckCount();
		(*m_pStoreMap)[(void*)pClassRef] = (void*)m_nMapCount++;
	}
}

</pre><pre>CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested,
	UINT* pSchema, DWORD* pObTag)
{
	ASSERT(pClassRefRequested == NULL ||
		AfxIsValidAddress(pClassRefRequested, sizeof(CRuntimeClass), FALSE));
	ASSERT(IsLoading());    // proper direction

	if (pClassRefRequested != NULL &amp;&amp; pClassRefRequested-&gt; m_wSchema == 0xFFFF)
	{
		TRACE1("Warning: Cannot call ReadClass/ReadObject for %hs.\n",
			pClassRefRequested-&gt; m_lpszClassName);
		AfxThrowNotSupportedException();
	}

	// make sure m_pLoadArray is initialized
	MapObject(NULL);

	// read object tag - if prefixed by wBigObjectTag then DWORD tag follows
	DWORD obTag;
	WORD wTag;
	*this &gt;&gt; wTag;
	if (wTag == wBigObjectTag)
		*this &gt;&gt; obTag;
	else
		obTag = ((wTag &amp; wClassTag) &lt;&lt; 16) | (wTag &amp; ~wClassTag);

	// check for object tag (throw exception if expecting class tag)
	if (!(obTag &amp; dwBigClassTag))
	{
		if (pObTag == NULL)
			AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);

		*pObTag = obTag;
		return NULL;
	}

	CRuntimeClass* pClassRef;
	UINT nSchema;
	if (wTag == wNewClassTag)
	{
		// new object follows a new class id
		if ((pClassRef = CRuntimeClass::Load(*this, &amp;nSchema)) == NULL)
			AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);

		// check nSchema against the expected schema
		if ((pClassRef-&gt; m_wSchema &amp; ~VERSIONABLE_SCHEMA) != nSchema)
		{
			if (!(pClassRef-&gt; m_wSchema &amp; VERSIONABLE_SCHEMA))
			{
				// schema doesn''t match and not marked as VERSIONABLE_SCHEMA
				AfxThrowArchiveException(CArchiveException::badSchema,
					m_strFileName);
			}
			else
			{
				// they differ -- store the schema for later retrieval
				if (m_pSchemaMap == NULL)
					m_pSchemaMap = new CMapPtrToPtr;
				ASSERT_VALID(m_pSchemaMap);
				m_pSchemaMap-&gt; SetAt(pClassRef, (void*)nSchema);
			}
		}
		CheckCount();
		m_pLoadArray-&gt; InsertAt(m_nMapCount++, pClassRef);
	}
	else
	{
		// existing class index in obTag followed by new object
		DWORD nClassIndex = (obTag &amp; ~dwBigClassTag);
		if (nClassIndex == 0 || nClassIndex &gt; (DWORD)m_pLoadArray-&gt; GetUpperBound())
			AfxThrowArchiveException(CArchiveException::badIndex,
				m_strFileName);

		pClassRef = (CRuntimeClass*)m_pLoadArray-&gt; GetAt(nClassIndex);
		ASSERT(pClassRef != NULL);

		// determine schema stored against objects of this type
		void* pTemp;
		BOOL bFound = FALSE;
		nSchema = 0;
		if (m_pSchemaMap != NULL)
		{
			bFound = m_pSchemaMap-&gt; Lookup( pClassRef, pTemp );
			if (bFound)
				nSchema = (UINT)pTemp;
		}
		if (!bFound)
			nSchema = pClassRef-&gt; m_wSchema &amp; ~VERSIONABLE_SCHEMA;
   }

	// check for correct derivation
	if (pClassRefRequested != NULL &amp;&amp;
		!pClassRef-&gt; IsDerivedFrom(pClassRefRequested))
	{
		AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
	}

	// store nSchema for later examination
	if (pSchema != NULL)
		*pSchema = nSchema;
	else
		m_nObjectSchema = nSchema;

	// store obTag for later examination
	if (pObTag != NULL)
		*pObTag = obTag;

	// return the resulting CRuntimeClass*
	return pClassRef;
}
</pre></div>
<img src ="http://www.cppblog.com/ivenher/aggbug/12459.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-14 15:17 <a href="http://www.cppblog.com/ivenher/articles/12459.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC漫谈（二）——对象的动态创建 </title><link>http://www.cppblog.com/ivenher/articles/12265.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Mon, 11 Sep 2006 07:20:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12265.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12265.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12265.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12265.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12265.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">接上次RTTI的话题。<br /><hr /><br />能够在运行时发现一个对象的类型，就可以在运行时动态的创建一个对象。在一个类库中，拥有统一的对象创建方式是非常重要的。<br /><p></p><p>在MFC中，对象的动态创建要依赖于RTTI所建立起来的类别型录，和动态创建有关的CRuntimeClass成员有两个：</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #000000" twffan="done">CObject</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> (PASCAL</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> m_pfnCreateObject)(); </span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 指向用于创建对象的函数</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done">CObject</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> CreateObject(); </span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 利用m_pfnCreateObject创建对象</span></div><p>利用RTTI建立的类别型录，DECLARE_DYNCREATE / IMPLEMENT_DYNCREATE继续为类添加了动态创建的功能。</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> DECLARE_DYNCREATE (class_name) \</span><span style="COLOR: #000000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />　　　　DECLARE_DYNAMIC (class_name) \ <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />　　　　</span><span style="COLOR: #0000ff" twffan="done">static</span><span style="COLOR: #000000" twffan="done"> CObject</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> PASCAL CreateObject();</span></div><p>这个宏同样用在类声明中，它不但为类添加了class##class_name对象和GetRuntimeClass()，还为类加入了一个静态函数CreateObject,用来进行对象的动态创建。同样IMPLEMENT_DYNCREATE用来对上面添加的内容作定义和初始化工作。</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> IMPLEMENT_DYNCREATE (class_name, base_class_name) \</span><span style="COLOR: #000000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />　　　　CObject</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> PASCAL class_name::CreateObject() \<br /><img id="Codehighlighter1_115_140_Open_Image" onclick="this.style.display='none'; Codehighlighter1_115_140_Open_Text.style.display='none'; Codehighlighter1_115_140_Closed_Image.style.display='inline'; Codehighlighter1_115_140_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_115_140_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_115_140_Closed_Text.style.display='none'; Codehighlighter1_115_140_Open_Image.style.display='inline'; Codehighlighter1_115_140_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" />　　　　</span><span id="Codehighlighter1_115_140_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_115_140_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{ </span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> </span><span style="COLOR: #0000ff" twffan="done">new</span><span style="COLOR: #000000" twffan="done"> class_name; }</span></span><span style="COLOR: #000000" twffan="done"> \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />　　　　IMPLEMENT_RUNTIMECLASS (class_name, base_class_name, </span><span style="COLOR: #000000" twffan="done">0xFFFF</span><span style="COLOR: #000000" twffan="done">, \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />　　　　class_name::CreateObject, NULL)</span></div><p>和IMPLEMENT_DYNAMIC不同的是，这里的IMPLEMENT_RUNTIMECLASS中的第4个参数并不为NULL，而是class_name::CreateObject，这样就指定了用于创建对象的函数，至于其它的内容，与RTTI没有什么不同。<br /><br />于是，整个对象的动态创建过程就变得非常简单了，只要我们找到某个特定类的CRuntimeClass对象，利用class##class_name.CreateObject()就可以了。</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #000000" twffan="done">CObject</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass::CreateObject()<br /><img id="Codehighlighter1_39_122_Open_Image" onclick="this.style.display='none'; Codehighlighter1_39_122_Open_Text.style.display='none'; Codehighlighter1_39_122_Closed_Image.style.display='inline'; Codehighlighter1_39_122_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_39_122_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_39_122_Closed_Text.style.display='none'; Codehighlighter1_39_122_Open_Image.style.display='inline'; Codehighlighter1_39_122_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" /></span><span id="Codehighlighter1_39_122_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_39_122_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />　　CObject</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> pObject </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"> NULL;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />　　pObject </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"> (</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">m_pfnCreateObject)();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />　　</span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> pObject;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" twffan="done" />}</span></span></div><p><font size="3"><strong>结论<br /></strong></font>想让你的类在MFC中支持动态创建，<br />1. 在类声明中使用DECLARE_DYNAMIC<br />2. 在类定义文件中使用IMPLEMENT_DYNAMIC，此时<br />    class##class_name.m_pfnCreateObject = class_name::CreateObject;　<br />    CRuntimeClass::CreateObject利用m_pfnCreateObject就可以进行对象的动态创建了<br /></p></font>
		</p>
<img src ="http://www.cppblog.com/ivenher/aggbug/12265.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-11 15:20 <a href="http://www.cppblog.com/ivenher/articles/12265.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC漫谈（一）——RTTI  （转）</title><link>http://www.cppblog.com/ivenher/articles/12264.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Mon, 11 Sep 2006 07:19:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12264.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12264.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12264.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12264.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12264.html</trackback:ping><description><![CDATA[
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">所有的这一系列的东西都来源于前天晚上的一个电话，内容大概是说：</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">“</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">你能教会我一个让我对</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">MFC</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">有点感觉的</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">Hello World</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">吗？我渴望一个像用</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">C</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">写的</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">Win32 Hello World</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">一样直观的例子。</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">”</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">想想这曾经是我学习</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">MFC</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">的时候也想到过的问题。我是一个喜欢刨根问底的人，喜欢把事情搞明白，于是曾经很长的一段时间里，我都困惑在纷繁杂乱的代码里。现在回想起来，侯捷老师的《</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">Dessecting MFC</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">》和</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">Jeff Prosise</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">的《</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">Programming MFC</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">》一起读来，估计能达到解惑的目的。当然，需要的是一点点耐心和对</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">Win32</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">程序的一点最基本的了解（貌似废话。。。）。于是那天晚上，</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">QQ</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">上和那个朋友聊了挺长一段时间，翻腾了一下</span>
		<span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">MFC</span>
		<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" twffan="done">的源代码，就有了这一系列的东西，全当是故地重游了一番。言归正传吧。文章中所有的代码都提取自MFC 7.0<br /><hr /><br /><font face="Times New Roman">在MFC中，RTTI是依靠为彼此有继承关系的类建立一个记录其类型的链表来实现的，和RTTI有关的CRuntimeClass成员有4个：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #000000" twffan="done">LPCSTR m_lpszClassName;    </span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 用于记录类名<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 用于指向基类的CRuntimeClass结构</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done">CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> m_pBaseClass;  <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 用于指向链表中前一个类的CRuntimeClass结构</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done">CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> m_pNextClass;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 用于建立类别型录</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> AFX_CLASSINIT</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> m_pClassInit; </span></div><br />这样在这个类别型录中就有了许多条路径，每一条都是沿着m_pBaseClass一直可以找到某个类的最终基类。要把一个类加入到这个类别型录中要用到两个宏：<br /><span style="COLOR: #000000" twffan="done">DECLARE_DYNAMIC </span><span style="COLOR: #000000" twffan="done">/</span><span style="COLOR: #000000" twffan="done"> IMPLEMENT_DYNAMIC<br /></span>其中：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> DECLARE_DYNAMIC (class_name) \</span><span style="COLOR: #000000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #0000ff" twffan="done">public</span><span style="COLOR: #000000" twffan="done">: \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />    </span><span style="COLOR: #0000ff" twffan="done">static</span><span style="COLOR: #000000" twffan="done"> </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass </span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done">##class_name; \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />    </span><span style="COLOR: #0000ff" twffan="done">virtual</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> GetRuntimeClass() </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done">; \</span></div><br />这个宏是用在类声明中的，其作用就是根据类的名字为该类添加两个public的成员，分别用于记录类的型别和获得对象class##class_name的地址，注意这里的class##class_name是个静态成员，这就为后面我们做类型的比较奠定了基础（继承于同一个基类的派生类对象包含共同的静态类成员）。在类中使用了DECLARE_DYNAMIC后，还要在.cpp的文件中使用IMPLEMENT_DYNAMIC宏，该宏的作用就是初始化class##class_name对象和定义GetRuntimeClass函数。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> IMPLEMENT_DYNAMIC (class_name, base_class_name) \</span><span style="COLOR: #000000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />    IMPLEMENT_RUNTIMECLASS (class_name, base_class_name, </span><span style="COLOR: #000000" twffan="done">0xFFFF</span><span style="COLOR: #000000" twffan="done">, NULL, NULL)</span></div><br />IMPLEMENT_DYNAMIC在使用的时候，要指定类和其基类的名字，之后利用IMPLEMENT_RUNTIMECLASS进行实质性的初始化活动。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> IMPLEMENT_RUNTIMECLASS (class_name, base_class_name, wSchema, pfnNew, class_init) \</span><span style="COLOR: #000000" twffan="done"><br /><img id="Codehighlighter1_157_274_Open_Image" onclick="this.style.display='none'; Codehighlighter1_157_274_Open_Text.style.display='none'; Codehighlighter1_157_274_Closed_Image.style.display='inline'; Codehighlighter1_157_274_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_157_274_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_157_274_Closed_Text.style.display='none'; Codehighlighter1_157_274_Open_Image.style.display='inline'; Codehighlighter1_157_274_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" />    AFX_COMDAT </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass class_name::</span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done">##class_name </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"> </span><span id="Codehighlighter1_157_274_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_157_274_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{ \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />        　　#class_name, </span><span style="COLOR: #0000ff" twffan="done">sizeof</span><span style="COLOR: #000000" twffan="done">(</span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done"> class_name), wSchema, pfnNew, \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" twffan="done" />        　　RUNTIME_CLASS(base_class_name), NULL, class_init }</span></span><span style="COLOR: #000000" twffan="done">; \<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />    CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> class_name::GetRuntimeClass() </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> \<br /><img id="Codehighlighter1_337_374_Open_Image" onclick="this.style.display='none'; Codehighlighter1_337_374_Open_Text.style.display='none'; Codehighlighter1_337_374_Closed_Image.style.display='inline'; Codehighlighter1_337_374_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_337_374_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_337_374_Closed_Text.style.display='none'; Codehighlighter1_337_374_Open_Image.style.display='inline'; Codehighlighter1_337_374_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" />    </span><span id="Codehighlighter1_337_374_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_337_374_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{ </span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> RUNTIME_CLASS (class_name); }</span></span><span style="COLOR: #000000" twffan="done"> \</span></div><br />其中，在class#class_name的初始化中和RTTI相关的只有：<br />&amp;name_class用来初始化m_lpszClassName<br />RUNTIME_CLASS(base_class_name)用来初始化CRuntimeClass* m_pBaseClass<br />NULL用来初始化CRuntimeClass* m_pNextClass（此时类别型录还没有建立起来） 
<p>另外，RUNTIME_CLASS就是用来获得class##class_name对象地址的宏：<br /></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> RUNTIME_CLASS (class_name) _RUNTIME_CLASS (class_name)</span><span style="COLOR: #000000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /></span><span style="COLOR: #0000ff" twffan="done">#define</span><span style="COLOR: #000000" twffan="done"> _RUNTIME_CLASS (class_name) \</span><span style="COLOR: #000000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" />    ((CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done">) (</span><span style="COLOR: #000000" twffan="done">&amp;</span><span style="COLOR: #000000" twffan="done">class_name::</span><span style="COLOR: #0000ff" twffan="done">class</span><span style="COLOR: #000000" twffan="done">##class_name))</span></div><p>这样，当对程序中的每一个类都使用了DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC宏之后，就为该类在类别型录中进行了登记工作。当然，MFC中所有的类都派生于CObject，所以所有的路线最终都要在CObject处会合，由于CObject没有基类，所以它的CRuntimeClass对象并不能用上面的两个宏来实现，在objcore.cpp中，为CObject的classCObject对象单独作了初始化的工作：</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> </span><span style="COLOR: #0000ff" twffan="done">struct</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass CObject::classCObject </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"><br /><img id="Codehighlighter1_52_107_Open_Image" onclick="this.style.display='none'; Codehighlighter1_52_107_Open_Text.style.display='none'; Codehighlighter1_52_107_Closed_Image.style.display='inline'; Codehighlighter1_52_107_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_52_107_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_52_107_Closed_Text.style.display='none'; Codehighlighter1_52_107_Open_Image.style.display='inline'; Codehighlighter1_52_107_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" /> </span><span id="Codehighlighter1_52_107_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_52_107_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{ </span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">CObject</span><span style="COLOR: #000000" twffan="done">"</span><span style="COLOR: #000000" twffan="done">, </span><span style="COLOR: #0000ff" twffan="done">sizeof</span><span style="COLOR: #000000" twffan="done">(CObject), </span><span style="COLOR: #000000" twffan="done">0xffff</span><span style="COLOR: #000000" twffan="done">, NULL, NULL, NULL }</span></span><span style="COLOR: #000000" twffan="done">;</span></div><p>我们可以看到m_pBaseClass被初始化为NULL。另外，也单独实现了GetRuntimeClass():</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img id="Codehighlighter1_48_84_Open_Image" onclick="this.style.display='none'; Codehighlighter1_48_84_Open_Text.style.display='none'; Codehighlighter1_48_84_Closed_Image.style.display='inline'; Codehighlighter1_48_84_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_48_84_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_48_84_Closed_Text.style.display='none'; Codehighlighter1_48_84_Open_Image.style.display='inline'; Codehighlighter1_48_84_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" /><span style="COLOR: #000000" twffan="done">CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> CObject::GetRuntimeClass() </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> </span><span id="Codehighlighter1_48_84_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_48_84_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />    </span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> _RUNTIME_CLASS (CObject);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" twffan="done" />}</span></span></div><br /><p>至于_RUNTIME_CLASS，前面已经说过了。这样，如果想要把自己的类介绍给MFC，只要在类声明中使用DECLARE_DYNAMIC，在类的实现中加入IMPLEMENT_DYNAMIC<br />，就可以把自己注册到类别型录中了。至此，为了实现类对象的RTTI，我们已经做好了所有的准备工作，下面就来看一下它的实现，它主要是靠CObject中的IsKindOf函数完成的。</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" twffan="done" /><span style="COLOR: #000000" twffan="done">BOOL CObject::IsKindOf(</span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> pClass) </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"><br /><img id="Codehighlighter1_58_170_Open_Image" onclick="this.style.display='none'; Codehighlighter1_58_170_Open_Text.style.display='none'; Codehighlighter1_58_170_Closed_Image.style.display='inline'; Codehighlighter1_58_170_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_58_170_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_58_170_Closed_Text.style.display='none'; Codehighlighter1_58_170_Open_Image.style.display='inline'; Codehighlighter1_58_170_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" /></span><span id="Codehighlighter1_58_170_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_58_170_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" /> 　　</span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> 为了简洁，略去了不相关的代码</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done"> 　　CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> pClassThis </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"> GetRuntimeClass();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" /> 　　</span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> pClassThis</span><span style="COLOR: #000000" twffan="done">-&gt;</span><span style="COLOR: #000000" twffan="done">IsDerivedFrom(pClass);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" twffan="done" />}</span></span></div><p>这里，由于GetRuntimeClass是虚函数，所以pClassThis会指向调用IsKindOf函数的类对象的class##class_name，之后利用指向该对象的指针调用IsDerivedFrom：</p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee" twffan="done"><img id="Codehighlighter1_73_369_Open_Image" onclick="this.style.display='none'; Codehighlighter1_73_369_Open_Text.style.display='none'; Codehighlighter1_73_369_Closed_Image.style.display='inline'; Codehighlighter1_73_369_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_73_369_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_73_369_Closed_Text.style.display='none'; Codehighlighter1_73_369_Open_Image.style.display='inline'; Codehighlighter1_73_369_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" twffan="done" /><span style="COLOR: #000000" twffan="done">BOOL CRuntimeClass::IsDerivedFrom(</span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> pBaseClass) </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> </span><span id="Codehighlighter1_73_369_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_73_369_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />    </span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done">为了简洁，略去了不相关的代码</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done">    </span><span style="COLOR: #0000ff" twffan="done">if</span><span style="COLOR: #000000" twffan="done"> (pBaseClass </span><span style="COLOR: #000000" twffan="done">==</span><span style="COLOR: #000000" twffan="done"> NULL)<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />        </span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> FALSE;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />    </span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> simple SI case</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done">    </span><span style="COLOR: #0000ff" twffan="done">const</span><span style="COLOR: #000000" twffan="done"> CRuntimeClass</span><span style="COLOR: #000000" twffan="done">*</span><span style="COLOR: #000000" twffan="done"> pClassThis </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"> </span><span style="COLOR: #0000ff" twffan="done">this</span><span style="COLOR: #000000" twffan="done">;<br /><img id="Codehighlighter1_223_314_Open_Image" onclick="this.style.display='none'; Codehighlighter1_223_314_Open_Text.style.display='none'; Codehighlighter1_223_314_Closed_Image.style.display='inline'; Codehighlighter1_223_314_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" twffan="done" /><img id="Codehighlighter1_223_314_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_223_314_Closed_Text.style.display='none'; Codehighlighter1_223_314_Open_Image.style.display='inline'; Codehighlighter1_223_314_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" twffan="done" />    </span><span style="COLOR: #0000ff" twffan="done">while</span><span style="COLOR: #000000" twffan="done"> (pClassThis </span><span style="COLOR: #000000" twffan="done">!=</span><span style="COLOR: #000000" twffan="done"> NULL) </span><span id="Codehighlighter1_223_314_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff" twffan="done"><img src="http://www.cppblog.com/images/dot.gif" twffan="done" /></span><span id="Codehighlighter1_223_314_Open_Text" twffan="done"><span style="COLOR: #000000" twffan="done">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />        </span><span style="COLOR: #0000ff" twffan="done">if</span><span style="COLOR: #000000" twffan="done"> (pClassThis </span><span style="COLOR: #000000" twffan="done">==</span><span style="COLOR: #000000" twffan="done"> pBaseClass)<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />        　</span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> TRUE;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />        pClassThis </span><span style="COLOR: #000000" twffan="done">=</span><span style="COLOR: #000000" twffan="done"> pClassThis</span><span style="COLOR: #000000" twffan="done">-&gt;</span><span style="COLOR: #000000" twffan="done">m_pBaseClass;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" twffan="done" />    }</span></span><span style="COLOR: #000000" twffan="done">    <br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" twffan="done" />    </span><span style="COLOR: #0000ff" twffan="done">return</span><span style="COLOR: #000000" twffan="done"> FALSE;       </span><span style="COLOR: #008000" twffan="done">//</span><span style="COLOR: #008000" twffan="done"> walked to the top, no match</span><span style="COLOR: #008000" twffan="done"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" twffan="done" /></span><span style="COLOR: #000000" twffan="done">}</span></span></div><br />我们知道，派生类和基类共享基类的static对象，所以在这里，派生类和基类一定共享相同的class##class_name对象，这就为我们判定两个类是否有继承关系提供了理论基础，同样，在IsDerivedFrom中，while循环中的if也的确是这样做的，它沿着该类的同宗路线上行，只要不到共同的祖先CObject，就决不罢休。　<br /><br /><font size="3"><strong>结论</strong></font><br />如果想要把自己的类介绍给MFC，只要在类声明中使用DECLARE_DYNAMIC，在类的实现中加入IMPLEMENT_DYNAMIC<br />，就可以把自己注册到类别型录中了</font></span>
<img src ="http://www.cppblog.com/ivenher/aggbug/12264.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-11 15:19 <a href="http://www.cppblog.com/ivenher/articles/12264.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于 CFileDialog 对话框多选功能的一个问题</title><link>http://www.cppblog.com/ivenher/articles/12065.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Tue, 05 Sep 2006 15:58:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/12065.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/12065.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/12065.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/12065.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/12065.html</trackback:ping><description><![CDATA[作者：<a href="mailto:northtibet@sohu.com">Northtibet</a><p><a href="http://www.vckbase.com/code/downcode.asp?id=2782">下载源代码</a><br /><br />　　最近有位读者来信指出：<a href="http://www.vckbase.com/vckbase/vckbase26" target="_blank">《在线杂志》第26期</a>中有一篇文章：“<a href="http://vckbase.com/document/viewdoc/?id=940" target="_blank">再谈 CFileDialog 对话框的定制</a>”，其例子程序有一个bug。如果多选时选中的文件过多，那么后面选中的文件将无效，也就是说即使也白选,点击“确定”后没有任何操作 。本文将提供解决此问题的办法，并说明问题的来由。<br />　　一般我们都是象下面这样来设置具备多选能力的 CFileDialog： </p><pre>     // 首先创建一个 CFIleDialog 类实例，并设置多选标志
1     CFileDialog mFileDlg(TRUE, NULL,NULL, 
2                          OFN_ALLOWMULTISELECT,
3                          	_T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"), 
4                          AfxGetMainWnd()); 
5     CString pathName; 
6     If(mFileDlg.DoModal ()==IDOK)
7     { 
8         POSITION mPos=mFileDlg.GetStartPosition(); 
9         while(mPos!=NULL) 
10         { 
11              pathName=mFileDlg.GetNextPathName(mPos); 
12              TRACE("%s\n",pathName);
13	} 
14     }
15     else
16         TRACE(“IDCANCLE\n”);</pre>　　在大多数情况下，这段代码都能正常运行，但如果你选中的文件过多，那么后面选中的文件将不会被影响，选中无反应,点击“确定”也无操作。这是为什么呢？在上述代码段的第五行添加如下语句： <pre>	TRACE("nMaxFile :%d\n",mFileDlg.m_ofn.nMaxFile);</pre>　　编译并运行上述代码（具体细节参见本文例子程序），并用 TraceWin 跟踪 TRACE 输出，你会发现 nMaxFile 的输出是 260。如图所示：<br /><br /><img height="228" src="http://www.vckbase.com/document/journal/vckbase44/images/cfdtraceimg.gif" width="682" border="0" twffan="done" /><br /><br />　　问题就出在这里，nMaxFile 是 OPENFILENAME 结构的成员之一，MSDN 对之是这样解释的：<br /><b>nMaxFile：</b>说明 lpstrFile 缓冲指针的大小，以 TCHARs 为单位。对于 ANSI 版本，它指的是字节数。对于 Unicode 版本，它指的是字符数，该缓冲必须足够大才能存储文件的路径字符串，包括结尾空字符。如果 该缓存太小以至于无法包含文件信息，那么 GetOpenFileName 和 GetSaveFileName 函数将返回 FALSE。该缓冲至少要求容纳 256 个字符。<br />　　现在明白了吧，多选时，由于文件路径和名称的长度超过了限制，造成程序出现上述问题。解决办法是重新设置 nMaxFile 大小。 <pre>	#define  NAMEBUF   1024
	...
         mFileDlg.m_ofn.lpstrFile=new TCHAR[NAMEBUF];   // 重新定义 lpstrFile 缓冲大小
         memset(mFileDlg.m_ofn.lpstrFile,0,NAMEBUF);  // 初始化定义的缓冲 
		 mFileDlg.m_ofn.nMaxFile = NAMEBUF;           // 重定义 nMaxFile 
	...
         delete [] mFileDlg.m_ofn.lpstrFile;             // 切记使用完后释放资源		</pre>详细代码请参考本文例子代码。<br /><br /><img src ="http://www.cppblog.com/ivenher/aggbug/12065.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2006-09-05 23:58 <a href="http://www.cppblog.com/ivenher/articles/12065.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>INI文件编程</title><link>http://www.cppblog.com/ivenher/articles/2010.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 23 Dec 2005 08:06:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/2010.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/2010.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/2010.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/2010.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/2010.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:<BR>　　一.将信息写入.INI文件中.<BR>　　1.所用的WINAPI函数原型为:&nbsp;<BR>BOOL&nbsp;WritePrivateProfileString(<BR>LPCTSTR&nbsp;lpAppName,<BR>LPCTSTR&nbsp;lpKeyName,<BR>LPCTSTR&nbsp;lpString,<BR>LPCTSTR&nbsp;lpFileName<BR>);&nbsp;<BR>　　其中各参数的意义:<BR>　　　LPCTSTR&nbsp;lpAppName&nbsp;是INI文件中的一个字段名.<BR>　　　LPCTSTR&nbsp;lpKeyName&nbsp;是lpAppName下的一个键名,通俗讲就是变量名.<BR>　　　LPCTSTR&nbsp;lpString&nbsp;是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.<BR><BR>LPCTSTR&nbsp;lpFileName&nbsp;是完整的INI文件名.<BR><BR>2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入&nbsp;c:\stud\student.ini&nbsp;文件中.&nbsp;<BR><BR>CString&nbsp;strName,strTemp;<BR>int&nbsp;nAge;<BR>strName="张三";<BR>nAge=12;<BR>::WritePrivateProfileString("StudentInfo","Name",strName,"c:\\stud\\student.ini");&nbsp;<BR><BR>此时c:\stud\student.ini文件中的内容如下:<BR>[StudentInfo]<BR><BR>　　　Name=张三<BR>　　3.要将学生的年龄保存下来,只需将整型的值变为字符型即可:<BR>strTemp.Format("%d",nAge);<BR>::WritePrivateProfileString("StudentInfo","Age",strTemp,"c:\\stud\\student.ini");&nbsp;<BR><BR>　　二.将信息从INI文件中读入程序中的变量.<BR>　　1.所用的WINAPI函数原型为:<BR>DWORD&nbsp;GetPrivateProfileString(<BR>LPCTSTR&nbsp;lpAppName,&nbsp;<BR>LPCTSTR&nbsp;lpKeyName,&nbsp;<BR>LPCTSTR&nbsp;lpDefault,&nbsp;<BR>LPTSTR&nbsp;lpReturnedString,&nbsp;<BR>DWORD&nbsp;nSize,&nbsp;<BR>LPCTSTR&nbsp;lpFileName&nbsp;<BR>);&nbsp;<BR>　　其中各参数的意义:&nbsp;<BR>　　　前二个参数与&nbsp;WritePrivateProfileString中的意义一样.<BR><BR>　　　lpDefault&nbsp;:&nbsp;如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量.&nbsp;<BR>　　　lpReturnedString&nbsp;:&nbsp;接收INI文件中的值的CString对象,即目的缓存器.<BR>　　　nSize&nbsp;:&nbsp;目的缓存器的大小.<BR>　　　lpFileName&nbsp;:&nbsp;是完整的INI文件名.<BR>　　2.具体使用方法:现要将上一步中写入的学生的信息读入程序中.<BR>CString&nbsp;strStudName;<BR>int&nbsp;nStudAge;&nbsp;<BR>GetPrivateProfileString("StudentInfo","Name","默认姓名",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c:\\stud\\student.ini");&nbsp;<BR>　　执行后&nbsp;strStudName&nbsp;的值为:"张三",若前两个参数有误,其值为:"默认姓名".<BR><BR>　　3.读入整型值要用另一个WINAPI函数:&nbsp;<BR>UINT&nbsp;GetPrivateProfileInt(<BR>LPCTSTR&nbsp;lpAppName,&nbsp;<BR>LPCTSTR&nbsp;lpKeyName,&nbsp;<BR>INT&nbsp;nDefault,&nbsp;<BR>LPCTSTR&nbsp;lpFileName&nbsp;<BR>);&nbsp;<BR>　　这里的参数意义与上相同.使用方法如下:<BR><BR>nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c:\\stud\\student.ini");&nbsp;<BR><BR>　　三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下:<BR>　　1.写入:<BR>CString&nbsp;strTemp,strTempA;<BR>int&nbsp;i;<BR>int&nbsp;nCount=6;<BR>file://共有6个文件名需要保存<BR><BR>for(i=0;i&nbsp;{strTemp.Format("%d",i);<BR>strTempA=文件名;<BR>file://文件名可以从数组,列表框等处取得.<BR>::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,"c:\\usefile\\usefile.ini");<BR>}<BR>strTemp.Format("%d",nCount);<BR>::WritePrivateProfileString("FileCount","Count",strTemp,"c:\\usefile\\usefile.ini");<BR>file://将文件总数写入,以便读出.&nbsp;<BR><BR>　　2.读出:<BR>nCount=::GetPrivateProfileInt("FileCount","Count",0,"c:\\usefile\\usefile.ini");<BR>for(i=0;i&nbsp;{strTemp.Format("%d",i);<BR><BR>strTemp="FileName"+strTemp;<BR>::GetPrivateProfileString("CurrentIni",strTemp,"default.fil",&nbsp;strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c:\\usefile\\usefile.ini");<BR><BR>file://使用strTempA中的内容.<BR>}&nbsp;<BR><BR>　　补充四点:<BR><BR>　　　1.INI文件的路径必须完整,文件名前面的各级目录必须存在,否则写入不成功,该函数返回&nbsp;FALSE&nbsp;值.<BR><BR>　　　2.文件名的路径中必须为&nbsp;\\&nbsp;,因为在VC++中,&nbsp;\\&nbsp;才表示一个&nbsp;\&nbsp;.<BR><BR>　　　3.也可将INI文件放在程序所在目录,此时&nbsp;lpFileName&nbsp;参数为:&nbsp;".\\student.ini".<BR><BR>　　　4.从网页中粘贴源代码时,最好先粘贴至记事本中,再往VC中粘贴,否则易造成编译错误,开始时我也十分不解,好好的代码怎么就不对呢?后来才找到这个方法.还有一些代码中使用了全角字符如:＜，＼等,也会<BR>造成编译错误.<BR><BR>INI文件编程<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;INI文件在系统配置及应用程序参数保存与设置方面，具有很重要的作用，所以可视化的编程一族，如VB、VC、VFP、Delphi等都提供了读写INI文件的方法，其中Delphi中操作INI文件，最为简洁，这是因为Delphi3提供了一个TInifile类，使我们可以非常灵活的处理INI文件。&nbsp;<BR><BR>一、有必要了解INI文件的结构：<BR>;注释<BR>[小节名]<BR>关键字=值<BR>...<BR>　&nbsp;INI文件允许有多个小节，每个小节又允许有多个关键字，&nbsp;"="后面是该关键字的值。&nbsp;<BR>　&nbsp;值的类型有三种：字符串、整型数值和布尔值。其中字符串存贮在INI文件中时没有引号，<BR>布尔真值用1表示，布尔假值用0表示。&nbsp;<BR>　&nbsp;注释以分号";"开头。&nbsp;<BR><img src ="http://www.cppblog.com/ivenher/aggbug/2010.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-12-23 16:06 <a href="http://www.cppblog.com/ivenher/articles/2010.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>删除自己的程序</title><link>http://www.cppblog.com/ivenher/articles/1846.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Sat, 17 Dec 2005 06:59:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1846.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1846.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1846.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1846.html</trackback:ping><description><![CDATA[<P>#include &lt;windows.h&gt;<BR>#include &lt;tchar.h&gt;<BR>#include &lt;stdio.h&gt;<BR>#include &lt;shlobj.h&gt;<BR>#include &lt;shlwapi.h&gt;</P>
<P><BR>BOOL SelfDelete()<BR>{<BR>&nbsp;TCHAR szModule [MAX_PATH],<BR>&nbsp;&nbsp;&nbsp; szComspec[MAX_PATH],<BR>&nbsp;&nbsp;&nbsp; szParams [MAX_PATH];</P>
<P>&nbsp;// get file path names:<BR>&nbsp;if((GetModuleFileName(0,szModule,MAX_PATH)!=0) &amp;&amp;<BR>&nbsp;&nbsp;&nbsp; (GetShortPathName(szModule,szModule,MAX_PATH)!=0) &amp;&amp;<BR>&nbsp;&nbsp;&nbsp; (GetEnvironmentVariable("COMSPEC",szComspec,MAX_PATH)!=0))<BR>&nbsp;{<BR>&nbsp;&nbsp;// set command shell parameters<BR>&nbsp;&nbsp;lstrcpy(szParams," /c&nbsp; del ");<BR>&nbsp;&nbsp;lstrcat(szParams, szModule);<BR>&nbsp;&nbsp;lstrcat(szParams, " &gt; nul");<BR>&nbsp;&nbsp;lstrcat(szComspec, szParams);</P>
<P><BR>&nbsp;&nbsp;// set struct members<BR>&nbsp;&nbsp;STARTUPINFO&nbsp;&nbsp;si={0};<BR>&nbsp;&nbsp;PROCESS_INFORMATION&nbsp;pi={0};<BR>&nbsp;&nbsp;si.cb = sizeof(si);<BR>&nbsp;&nbsp;si.dwFlags = STARTF_USESHOWWINDOW;<BR>&nbsp;&nbsp;si.wShowWindow = SW_HIDE;</P>
<P>&nbsp;&nbsp;// increase resource allocation to program<BR>&nbsp;&nbsp;SetPriorityClass(GetCurrentProcess(),<BR>&nbsp;&nbsp;&nbsp;&nbsp;REALTIME_PRIORITY_CLASS);<BR>&nbsp;&nbsp;SetThreadPriority(GetCurrentThread(),<BR>&nbsp;&nbsp;&nbsp;THREAD_PRIORITY_TIME_CRITICAL);</P>
<P>&nbsp;&nbsp;// invoke command shell<BR>&nbsp;&nbsp;if(CreateProcess(0, szComspec, 0, 0, 0,CREATE_SUSPENDED|<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DETACHED_PROCESS, 0, 0, &amp;si, &amp;pi))<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;// suppress command shell process until program exits<BR>&nbsp;&nbsp;&nbsp;SetPriorityClass(pi.hProcess,IDLE_PRIORITY_CLASS);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetThreadPriority(pi.hThread,THREAD_PRIORITY_IDLE); </P>
<P>&nbsp;&nbsp;&nbsp;// resume shell process with new low priority<BR>&nbsp;&nbsp;&nbsp;ResumeThread(pi.hThread);</P>
<P>&nbsp;&nbsp;&nbsp;// everything seemed to work<BR>&nbsp;&nbsp;&nbsp;return TRUE;<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;else // if error, normalize allocation<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;SetPriorityClass(GetCurrentProcess(),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NORMAL_PRIORITY_CLASS);<BR>&nbsp;&nbsp;&nbsp;SetThreadPriority(GetCurrentThread(),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THREAD_PRIORITY_NORMAL);<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>&nbsp;return FALSE;<BR>}<BR>&nbsp;<BR>int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) <BR>{<BR>&nbsp;<BR>&nbsp;TCHAR&nbsp;&nbsp; sImeFile[MAX_PATH],<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; szDir[MAX_PATH];</P>
<P><BR>&nbsp;&nbsp;&nbsp; MessageBox(NULL, _T("now delete myselef ?\n"), "Warning", MB_OK); <BR>&nbsp;</P>
<P>//&nbsp;if(!DelIMEFile(hInstance, sImeFile))<BR>//&nbsp;&nbsp;return FALSE;<BR>&nbsp;&nbsp;&nbsp; <BR>//&nbsp;&nbsp;&nbsp; DelReg();<BR>&nbsp;</P>
<P>&nbsp;&nbsp; &nbsp;SelfDelete();</P>
<P>}</P><img src ="http://www.cppblog.com/ivenher/aggbug/1846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-12-17 14:59 <a href="http://www.cppblog.com/ivenher/articles/1846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++ 6.0的文档/视结构</title><link>http://www.cppblog.com/ivenher/articles/1792.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 15 Dec 2005 05:55:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1792.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1792.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1792.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1792.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Visual&nbsp;C++&nbsp;6.0&nbsp;以其功能强大、用户界面友好而倍受程序员们的青睐。但是，在当前的Microsoft&nbsp;基本类库4.2&nbsp;版本中，大约有将近200&nbsp;个类，数千个函数，加之Microsoft&nbsp;公司隐藏了一些技术细节，使得人们深入学习MFC变得十分困难。&nbsp;<BR><BR>　　MFC的AppWizard可以生成三种类型的应用程序：基于对话框的应用、单文档应用（SDI）和多文档应用（MDI）。前两者的结构较简单，本文不再赘叙。笔者拟从MFC中的文档/视结构入手，分析一些函数的流程，并解决编制MDI&nbsp;应用程序过程中的一些常见问题。&nbsp;<BR><BR>（一）、了解文档/视结构&nbsp;<BR><BR>　　MFC应用程序模型历经多年以有了相当大的发展。有一个时期，它只是个使用应用程序对象和主窗口对象的简单模型。在这个模型中，应用程序的数据作为成员变量保持在框架窗口类中，在框架窗口的客户区中，该数据被提交显示器。随着MFC2。0的问世，一种应用程序结构的新方式----MFC文档/视结构出现了。在这种结构中，CFrameWnd繁重的任务被委派给几个不同类，实现了数据存储和显示的分离。一般情况下，采用文档/视结构的应用程序至少应由以下对象组成：&nbsp;<BR><BR>。应用程序是一个CwinApp派生对象，它充当全部应用程序的容器。应用程序沿消息映射网络分配消息给它的所有子程序。&nbsp;<BR>。框架窗口是一CfrmeWnd派生对象。&nbsp;<BR>。文档是一个CDocument派生对象，它存储应用程序的数据，并把这些信息提供给应用程序的其余部分。&nbsp;<BR>。视窗是Cview派生对象，它与其父框架窗口用户区对齐。视窗接受用户对应用程序的输入并显示相关联的文档数据。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常，应用程序数据存在于简单模型中的框架窗口中。在文档/视方式中，该数据移入称为document的独立数据对象。当然，文档不一定是文字，文档是可以表现应用程序使用的数据集的抽象术语。而用户输入处理及图形输出功能从框架窗口转向视图。单独的视窗完全遮蔽框架窗口的客户区，这意味着即使程序员直接绘画至框架窗口的客户区，视图仍遮蔽绘画，在屏幕上不出现任何信息。所以输出必须通过视图。框架窗口仅仅是个视图容器。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDocument类对文档的建立及归档提供支持并提供应用程序用于控制其数据的接口。MDI应用程序可以处理多个类型的文档，每个类型的文档拥有一个相关联的文档模板对象。文档对象驻留在场景后面，提供由视图对象显示的信息。文档至少有一个相关联的视图。视图只能与一个文档相关联。<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在文档/视方式中，对象的建立是由文档模板来管理的，它是CDocTemplate派生对象，建立并维护框架窗口，文档及视。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MFC调用命令处理程序以响应发生在应用程序中的事件。命令发送的优先级是：&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;活动的视图-&gt;框架窗口-&gt;文档-&gt;应用程序-&gt;默认窗口过程(DefWindowsProc)&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;总之，在文档/视方式中，文档和视是分离的，即：文档用于保存数据，而视是用来显示这些数据。文档模板维护它们之间的关西。这种文档/视结构在开发大型软件项目时特别有用。&nbsp;<BR><BR>（二）、了解与文档/视结构有关的各种类之间的关系。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在文档/视应用程序中，CWinApp对象拥有并控制文档模板，后者产生文档、框架窗口及视窗。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从用户的角度来看，“视”实际上是一个普通的窗口。象其他基于Widnows应用的窗口一样，人们可以改变它的尺寸，对它进行移动，也可以随时关闭它。若从程序员的角度来看，视实际上是一个从MFC类库中的Cview类所派生出的类的对象。文档对象是用来保存数据的，而视对象是用来显示数据的，并且允许对数据进行编辑。SDI或MDI的文档类是由Cdocument类派生出来的，它可以有一个或多个视类，而这些视类最终都是由Cview类派生出来的。视对象只有一个与之相联系的文档对象，它所包含的CView::GetDocument函数允许应用在视中得到与之相联系的文档，据此，应用程序可以对文档类成员函数及公共数据成员进行访问。如果视对象接受到了一条消息，表示用户在编辑控制中输入了新的数据，此时，视就必须通知文档对象对其内部数据进行相应的更新。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果文档数据发生了变化，则所有的视都必须被通知到，以便它们能够对所显示的数据进行相应的更新。Cdocument::UpdateAllViews函数即可完成此功能。当该函数被调用时，派生视类的CView::OnUpdate函数被触发。通常OnUpdate函数要对文档进行访问，读取文档数据，然后再对视的数据成员或控制进行更新，以便反映出文档的变化。另外，还可以利用OnUpdate函数使视的部分客户区无效，以便触发Cview::OnDraw函数，利用文档数据来重新对窗口进行绘制。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在MDI应用程序中，可以处理多个文档类型，即多个文档模板，每个模板又可以有多个文档，每个文档又可以多视显示。为管理方便，上一级往往保留了下一级的指针列表。解释如下：&nbsp;<BR><BR>（1）、每个应用程序类(CwinApp的派生类)都保留并维护了一份所有文档模板的指针列表，这是一个链表结构。应用程序为所要支持的每个文档类型动态分配一个CMultiDocTemplate&nbsp;对象，&nbsp;<BR>CmultiDocTemplate(UINT&nbsp;nIDResource,&nbsp;<BR>CruntimeClass&nbsp;*&nbsp;pDocClass,&nbsp;<BR>CruntimeClass&nbsp;*&nbsp;pFrameClass,&nbsp;<BR>CruntimeClass&nbsp;*&nbsp;pViewClass&nbsp;);&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;并在应用程序类的CWinApp::InitInstance成员函数中将每个CMultiDocTemplate对象传递给CWinApp::AddDocTemplate。&nbsp;该函数将一个文档模板加入到应用程序可用文档模板的列表中。函数原形为：&nbsp;<BR><BR>void&nbsp;AddDocTemplate(CdocTemplate&nbsp;*&nbsp;pTemplate);&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;应用程序可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板的位置，利用该值来调用CWinApp::GetNextDocTemplate函数，获得第一个CDocTemplate对象指针。函数原形如下：<BR>&nbsp;<BR>POSITION&nbsp;GetFirstDocTemplate(&nbsp;)&nbsp;const;&nbsp;<BR>CDocTemplate&nbsp;*GetNextDocTemplate(&nbsp;POSITION&nbsp;&amp;&nbsp;pos&nbsp;)&nbsp;const;&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第二个函数返回由pos&nbsp;标识的文档模板。POSITION是MFC定义的一个用于迭代或对象指针检索的值。通过这两个函数，应用程序可以遍历整个文档模板列表。如果被检索的文档模板是模板列表中的最后一个，则pos参数被置为NULL。&nbsp;<BR><BR>（2）、一个文档模板可以有多个文档，每个文档模板都保留并维护了一个所有对应文档的指针列表。应用程序可以用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一个文档的位置，并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与模板相关的文档列表。函数原形为：<BR>&nbsp;<BR>viaual&nbsp;POSITION&nbsp;GetFirstDocPosition(&nbsp;)&nbsp;const&nbsp;=&nbsp;0;&nbsp;<BR>visual&nbsp;Cdocument&nbsp;*GetNextDoc(POSITION&nbsp;&amp;&nbsp;rPos)&nbsp;const&nbsp;=&nbsp;0;&nbsp;<BR><BR>如果列表为空，则rPos被置为NULL.&nbsp;<BR><BR>（3）、在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。函数原形如下：&nbsp;<BR><BR>CDocTemplate&nbsp;*&nbsp;GetDocTemplate&nbsp;(&nbsp;)&nbsp;const;&nbsp;<BR><BR>如果该文档不属于文档模板管理，则返回值为NULL。&nbsp;<BR><BR>（4）、一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表。CDocument::AddView将一个视连接到文档上，将该视加入到文档相联系的视的列表中，并将视的文档指针指向该文档。当有File/New、File/Open、Windows/New或Window/Split的命令而将一个新创建的视的对象连接到文档上时，&nbsp;MFC会自动调用该函数，框架通过文档/视的结构将文档和视联系起来。当然，程序员也可以根据自己的需要调用该函数。&nbsp;<BR><BR>Virtual&nbsp;POSITION&nbsp;GetFirstViewPosition(&nbsp;)&nbsp;const;&nbsp;<BR>Virtual&nbsp;CViw&nbsp;*&nbsp;GetNextView(&nbsp;POSITION&nbsp;&amp;rPosition)&nbsp;cosnt;&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的列表中的第一个视的位置，并调用CDocument::GetNextView返回指定位置的视，并将rPositon的值置为列表中下一个视的POSITION值。如果找到的视为列表中的最后一个视，则将rPosition置为NULL.&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当在文档上新增一个视或删除一个视时，MFC会调用OnChangeViewList函数。如果被删除的视是该文档的最后一个视，则删除该文档。&nbsp;<BR><BR>（5）、一个视只能有一个文档。在视中，调用CView::GetDocument可以获得一个指向视的文档的指针。函数原形如下：&nbsp;<BR><BR>CDocument&nbsp;*GetDocument&nbsp;(&nbsp;)&nbsp;const;&nbsp;<BR><BR>如果该视不与任何文档相，则返回NULL.&nbsp;<BR><BR>（6）、MDI框架窗口通过调用CFrameWnd::GetActiveDocument&nbsp;可以获得与当前活动的视相连的CDocument&nbsp;指针。函数原形如下：&nbsp;<BR><BR>virtual&nbsp;CDocument&nbsp;*&nbsp;GetActiveDocument(&nbsp;);&nbsp;<BR><BR>（7）、通过调用CFrameWnd::GetActiveView&nbsp;可以获得指向与CFrameWnd框架窗口连接的活动视的指针，如果是被CMDIFrameWnd框架窗口调用，则返回NULL。MDI框架窗口可以首先调用MDIGetActive找到活动的MDI子窗口，然后找到该子窗口的活动视。函数原形如下：&nbsp;<BR><BR>virtual&nbsp;Cdocument&nbsp;*&nbsp;GetActiveDocument(&nbsp;);&nbsp;<BR><BR>（8）、MDI框架窗口通过调用CFrameWnd::GetActiveFrame,&nbsp;可以获得一个指向MDI框架窗口的活动多文档界面子窗口的指针。&nbsp;<BR><BR>（9）、CMDIChildWnd调用GetMDIFrame获得MDI框架窗口(CMDIFrameWnd)。&nbsp;<BR><BR>（10）、CWinApp&nbsp;调用AfxGetMainWnd得到指向应用程序的活动主窗口的指针。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面一段代码，就是利用CDocTemplate、CDocument和CView之间的存取关系，遍历整个文档模板、文档以及视。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMyApp&nbsp;*&nbsp;pMyApp&nbsp;=&nbsp;(CMyApp&nbsp;*)AfxGetApp();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;POSITION&nbsp;p&nbsp;=&nbsp;pMyApp-&gt;GetFirstDocTemplatePosition();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(p!=&nbsp;NULL)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDocTemplate&nbsp;*&nbsp;pDocTemplate&nbsp;=&nbsp;pMyApp-&gt;GetNextDocTemplate(p);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;POSITION&nbsp;p1&nbsp;=&nbsp;pDocTemplate-&gt;GetFirstDocPosition();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(p1&nbsp;!=&nbsp;NULL)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CDocument&nbsp;*&nbsp;pDocument&nbsp;=&nbsp;pDocTemplate-&gt;GetNextDoc(p1);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;POSITION&nbsp;p2&nbsp;=&nbsp;pDocument-&gt;GetFirstViewPosition();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(p2&nbsp;!=&nbsp;NULL)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CView&nbsp;*&nbsp;pView&nbsp;=&nbsp;pDocument-&gt;GetNextView(p2);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>}&nbsp;<BR><BR>（图4）、遍历整个文档模板、文档和视&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在应用程序的任何地方，程序员都可以调用AfxGetApp(&nbsp;)获得应用程序的对象指针。由于本文着重介绍文档/视的关系，至于框架窗口之间的关系没能列全，读者可以查相应的文档。&nbsp;<BR><BR>（三）、了解CwinApp::OnFileNew、CwinApp::OnFileOpen和Window/New的程序流程。&nbsp;<BR><BR>（1）、CwinApp::OnFileNew和CwinApp::OnFileOpen函数的简单流程。&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR>--------------------------------------------------------------------------------&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在CWinApp::OnFile/new&nbsp;或CwinApp::OnFileOpen函数中，核心操作是CDocTemplate::OpenDocument函数。其函数原型为：&nbsp;<BR><BR>virtual&nbsp;CDocument*&nbsp;CDocTemplate::OpenDocumentFile(LPCTSTR&nbsp;lpszPathName,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bMakeVisible&nbsp;=TRUE&nbsp;)&nbsp;=&nbsp;0;&nbsp;<BR><BR>图（4）中星号标注之后即是该函数的流程，简要介绍如下：&nbsp;<BR><BR>（1）、CDocTemplate::CreateNewDocument函数创建一个新文档，其类型与文档模板相关，并通过函数CDocTemplate::AddDocument加入该文档模板的文档指针列表中。此时，文档类的构造函数被执行，程序可以在此进行文档的初始化。&nbsp;<BR><BR>（2）、函数CDocTemplate::CreateNewFrame调用MDI子窗口类(CMDIChildWnd)的构造函数,生成MDI子窗口对象。接着调用CMDIChildWnd::PreCreateWindow。然后，生成一个CCreateContext对象,（CcreateContext是MFC框架所使用的一种结构，它将构成文档和视的组件联系起来。后文将详细介绍之。）并将该对象值传给CMDIChildWnd::OnCreateClient函数。MFC调用此函数，用CCreateContext对象提供的信息创建一个或多个CView对象。此时，各视的构造函数被依次调用。&nbsp;<BR><BR>（3）、接着，判断lpszPathName是否为空。分为两种情况：&nbsp;<BR><BR>(a)、若为空，则表明要创建一个新文档：调用SetDefaultTitle函数装载文档的缺省标题，并显示在文档的标题栏中；然后执行CDocument::OnNewDocument。该函数调用DeleteContents以保证文档为空，然后置新文档为清洁。可以重载该函数。&nbsp;<BR><BR>(b)、否则，表明要打开一个已存在的文档：调用CDocument::OnOpenDocument打开指定的文件；执行DeleteContext，保证文档为空；调用CObject::Serialize读入该文件的内容。（程序员可在此进行文件的读入操作。当然，也可以在CDocument::OnOpenDocument中读入文件）。然后置文档为清洁；最后，调用CDocTemplate::SetPathName，并把文件名加入到最近文件列表中。<BR>&nbsp;<BR>（4）、调用CDocTemplate::InitialUpdateFrame函数，使框架窗口中的各个视收到OnInitialUpdate调用。框架窗口的主视（子窗ID等于AFX_IDW_PANE_FIRST的视）被激活。程序员可以在此对视对象进行初始化。&nbsp;<BR><BR>（2）、Window/New命令的程序流程&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当主框架窗口上有子窗口时，选择Window/New命令可以生成该活动子窗口的影象。它们有相同的文档模板、相同的文档。其流程如下：&nbsp;<BR>　&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;执行Window/New的过程与File/New的过程差不多。所不同的是，File/New须要创建一个新文档，而Window/New则是获得已存在的MDI子窗口的文档。因此以前存在的视和New以后生成的视均为该文档的视，都是该文档的内容的显示。当调用CDocument::UpdateAllViews函数时，它们(视)的OnUpdate函数都将被激活。此时，在该文档的视指针列表中，将有多于一个的视（具体数目视Window/New执行的次数而定）。读者可以利用（图3）中的代码跟踪程序结果。&nbsp;<BR>　&nbsp;<BR>（四）、几种情况的讨论&nbsp;<BR><BR>上面，笔者就MFC中文档/视的关系进行了分析，下面，笔者将结合具体情况进行讨论：&nbsp;<BR><BR>（1）、如何根据自己的要求来选择文档模板，及相应的视和文档。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在通常的MDI应用程序中，只有一个文档模板，程序员只能打开一种类型的文档。因此，程序员只要调用File/New或者File/Open创建或者打开文档即可，至于文档、视和框架窗口之间的关系，由文档模板在幕后控制，不须要对文档模板进行操作。但是，如果应用程序需要处理多种类型的文档，并且何时打开何种文档均需程序员手工控制，此时，程序员必须对文档模板进行编程。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;例如，笔者需要处理AVI和BMP两种文件类型。AVI和BMP的数据存放格式不同，不能用同一的数据结构来描述，因此，把它们的数据都存入一个文档是不合适的。同时，由于AVI是图象序列，BMP仅是一幅图象，它们的显示是肯定不一样的，即它门的视不同。基于此，笔者决定分别建立两套文档模板，两套框架窗口，两套文档和两套视，分别用于AVI和BMP的数据存放和显示。程序可以根据用户选择的文件名来分别处理AVI和BMP。具体步骤如下：&nbsp;<BR><BR>（Step&nbsp;1）、在应用程序类(CWinApp)的派生类中增加文档模板成员变量，以便对文档模板进行操作。&nbsp;<BR><BR>class&nbsp;C3dlcsApp&nbsp;:&nbsp;public&nbsp;CWinApp&nbsp;<BR>{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......<BR>public:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMultiDocTemplate&nbsp;*&nbsp;m_pAVIDocTemplate;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMultiDocTemplate&nbsp;*&nbsp;m_pBMPDocTemplate;&nbsp;<BR>}&nbsp;<BR><BR>（Step&nbsp;2）、在主框架中增加菜单响应：&nbsp;<BR><BR>void&nbsp;CMainFrame::OnFileOpen()&nbsp;<BR>{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CFileDialog&nbsp;my(true);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(my.DoModal()==IDOK)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CString&nbsp;FileName&nbsp;=&nbsp;my.GetPathName();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CString&nbsp;FileExt&nbsp;=&nbsp;my.GetFileExt();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if((FileExt&nbsp;==&nbsp;"AVI")&nbsp;||&nbsp;(FileExt&nbsp;==&nbsp;"avi"))&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMyApp&nbsp;*&nbsp;pMyApp&nbsp;=&nbsp;(CMyApp&nbsp;*)AfxGetApp();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMultiDocTemplate*pAVIDocTemplate=pMyApp-&gt;m_pAVIDocTemplate;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pAVIDocTemplate-&gt;OpenDocumentFile(FileName);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if((FileExt&nbsp;==&nbsp;"BMP")&nbsp;||&nbsp;(FileExt&nbsp;==&nbsp;"bmp"))&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMyApp&nbsp;*&nbsp;p3dlcsApp&nbsp;=&nbsp;(CMyApp&nbsp;*)AfxGetApp();&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMultiDocTemplate*&nbsp;pDATDocTemplate=pMyApp-&gt;m_pBMPDocTemplate;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pDATDocTemplate-&gt;OpenDocumentFile(FileName);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AfxMessageBox("Yor&nbsp;select&nbsp;a&nbsp;file&nbsp;not&nbsp;supported!");&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<BR>}&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;笔者把用户输入文件名的后缀作为分支条件，如果是AVI文件，则先获得关于AVI文件的文档模板，然后调用CDocTemplate::OpenUpdateFrame&nbsp;(lpszFileName)函数打开此文档。正如前面所分析，此函数将依次生成新文档，新框架，在CMDIChildWnd::OnCreateClient中创建视，最后向框架中所有的视发送初始化消息，使其显示在屏幕上。如果是BMP文件，操作类似。<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当然，程序员也可以在程序的任何位置实现此操作：通过全局函数AfxGetApp&nbsp;获得应用程序对象指针，从而获得相应的文档模板指针。<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于由AppWizard生成的应用程序会缺省调用CWinApp::OnFileNew，所以当程序开始执行时，会在主框架上显示一个新的空窗口。如果想去掉这个空窗口，只须重载CWinApp::OnFileNew函数，不许要任何代码，即可。&nbsp;<BR>　&nbsp;<BR>（2）、切分窗口与文档/视结构&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个文档可以有多个视，切分窗口即是表示多视的一种方法。&nbsp;切分窗口是通过类CSplitterWnd来表示的，对Window来说，CSplitterWnd对象是一个真正的窗口，它完全占据了框架窗口的客户区域，而视窗口则占据了切分窗口的窗片区域。切分窗口并不参与命令传递机制，（窗片中）活动的视窗从逻辑上来看直接被连到了它的框架窗口中。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;切分窗口可以分为动态和静态两种。前者较简单，本文仅讨论后者。创建切分窗口的步骤如下：&nbsp;<BR><BR>（Step&nbsp;1）、在自己的框架窗口中声明成员变量，用以对切分窗口进行操作。&nbsp;<BR><BR>class&nbsp;CMyFrame&nbsp;:&nbsp;public&nbsp;CMDIChildWnd&nbsp;<BR>{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSplitterWnd&nbsp;m_Splitter;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSplitterWnd&nbsp;m_Splitter2;&nbsp;<BR>}&nbsp;<BR><BR>（Step&nbsp;2）、重载CMDIChildWnd::OnCreateClient函数，创建切分窗口。&nbsp;<BR><BR>BOOL&nbsp;CMyFrame::OnCreateClient(LPCREATESTRUCT&nbsp;lpcs,&nbsp;CCreateContext*&nbsp;pContext)&nbsp;<BR>{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;btn&nbsp;=&nbsp;m_Splitter.CreateStatic(this,1,2);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;btn&nbsp;|=&nbsp;m_Splitter.CreateView(0,0,&nbsp;RUNTIME_CLASS(CAVIDispView),&nbsp;CSize(100,100),&nbsp;pContext);&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_Splitter2.CreateStatic(&amp;m_Splitter,&nbsp;2,&nbsp;1,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WS_CHILD&nbsp;|&nbsp;WS_VISIBLE&nbsp;|&nbsp;WS_BORDER,&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_Splitter.IdFromRowCol(0,&nbsp;1));&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;btn&nbsp;|=&nbsp;m_Splitter2.CreateView(0,&nbsp;0,&nbsp;RUNTIME_CLASS(CBMPView),&nbsp;CSize(100,100),&nbsp;pContext);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;btn&nbsp;|=&nbsp;m_Splitter2.CreateView(1,&nbsp;0,&nbsp;RUNTIME_CLASS(CAVIView),&nbsp;CSize(100,100),&nbsp;pContext);&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;btn;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//return&nbsp;CMDIChildWnd::OnCreateClient(lpcs,&nbsp;pContext);&nbsp;<BR>}&nbsp;<BR><BR>CFrameWnd::OnCreateClient函数原形为：&nbsp;<BR><BR>virtual&nbsp;BOOL&nbsp;OnCreateClient(LPCREATESTRUCT&nbsp;lpcs,&nbsp;CcreateContext&nbsp;*&nbsp;pContext);&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;缺省的CMDIChildWnd::OnCreateClient函数根据pContext参数提供的信息，调用CFrameWnd::CreateView函数创建一个视。可以重载该函数，加载CCreateContext对象中传递的值，或改变框架窗口主客户区中控制的创建方式。在上面的程序中，笔者&nbsp;创建了3个切分窗口。比如打开了一个名为“a.avi”的文档，此时该文档将有3个视，一个框架窗口。如果执行了Window/New操作，则此时有一个文档，6个视和2个框架窗口。若该文档调用CDocument::UpdateAllViews函数，则这6个视的CView::OnUpdate函数都会被激发。&nbsp;<BR><BR>(3)、关于CCreateContext的讨论。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CCreateContext是MFC框架所使用的一种结构，它将构成文档/视的组件联系起来。这个结构包括指向文档的指针，框架窗口，视以及文档模板，它还包含一个指向CRuntimeClass的指针，以指明所创建的视的类型。其数据成员如下：&nbsp;<BR><BR>m_pNewViewClass：指向创建上下文的视的CRuntimeClass的指针。&nbsp;<BR>m_pCurrentDoc：指向文档对象的指针，以和新视联系起来。&nbsp;<BR>m_pNewDocTemplate：指向与框架窗口的创建相联系文档模板的指针。&nbsp;<BR>m_pLastView：指向已存在的视，它是新产生的视的模型。&nbsp;<BR>m_pCurrentFrame：指向已存在的框架窗口，它是新产生的框架窗口的模型。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;程序员可以通过改变CCreateContext对象的值，来创建更加灵活的视。由于过程较复杂，笔者不再赘许叙，读者可参阅相关的Visual&nbsp;C++&nbsp;Help文档。&nbsp;<BR><BR>（五）、结束语&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Visual&nbsp;C++&nbsp;6.0的文档/视结构代表了一种新的程序设计方式，其核心是文档与视的分离，即数据存放与显示（操作）的分离。在MFC类库中，各个对象之间的关系很复杂，但，只要深入了解后，会发现它们之间是相互联系的，可以相互存取的。如果大家想设计出灵活、健壮的应用程序，就必须深入了解MFC。跟踪原代码就是一个较好的方法。文档/视的关系的确非常复杂，如果能知道每个函数是在哪调用的，执行了何种操作，就能游人刃有余，写出优美的应用程序。<img src ="http://www.cppblog.com/ivenher/aggbug/1792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-12-15 13:55 <a href="http://www.cppblog.com/ivenher/articles/1792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提升进程权限</title><link>http://www.cppblog.com/ivenher/articles/1791.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Thu, 15 Dec 2005 05:35:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1791.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1791.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1791.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1791.html</trackback:ping><description><![CDATA[<BR>//&nbsp;hProcess&nbsp;[in]&nbsp;:&nbsp;要提升的进程，目标进程<BR>//&nbsp;lpPrivilegeName&nbsp;[in]&nbsp;:&nbsp;要提升到的特权，目标特权<BR>//&nbsp;返回值&nbsp;:&nbsp;TRUE&nbsp;:&nbsp;成功;&nbsp;FALSE&nbsp;:&nbsp;失败<BR><BR>BOOL&nbsp;UpdateProcessPrivilege(&nbsp;HANDLE&nbsp;hProcess,&nbsp;LPCTSTR&nbsp;lpPrivilegeName&nbsp;=&nbsp;SE_DEBUG_NAME&nbsp;)<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hToken;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;::OpenProcessToken(&nbsp;hProcess,&nbsp;TOKEN_ALL_ACCESS,&nbsp;&amp;hToken&nbsp;)&nbsp;)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LUID&nbsp;destLuid;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;::LookupPrivilegeValue(&nbsp;NULL,&nbsp;lpPrivilegeName,&nbsp;&amp;destLuid&nbsp;)&nbsp;)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TOKEN_PRIVILEGES&nbsp;TokenPrivileges;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TokenPrivileges.PrivilegeCount&nbsp;=&nbsp;1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TokenPrivileges.Privileges[0].Attributes&nbsp;=&nbsp;SE_PRIVILEGE_ENABLED;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TokenPrivileges.Privileges[0].Luid&nbsp;=&nbsp;destLuid;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;iResult;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;iResult&nbsp;=&nbsp;::AdjustTokenPrivileges(&nbsp;hToken,&nbsp;FALSE,&nbsp;&amp;TokenPrivileges,&nbsp;0,&nbsp;NULL,&nbsp;NULL&nbsp;)&nbsp;)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TRUE;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;FALSE;<BR>}<BR><img src ="http://www.cppblog.com/ivenher/aggbug/1791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-12-15 13:35 <a href="http://www.cppblog.com/ivenher/articles/1791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC学习笔记</title><link>http://www.cppblog.com/ivenher/articles/1130.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Tue, 15 Nov 2005 06:53:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1130.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1130.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1130.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1130.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1130.html</trackback:ping><description><![CDATA[<STRONG>VC学习笔记9：几个指针<BR><BR></STRONG>为了在视类中能够调用放在其它类中的数据或函数，应该先获得相应类的指针。<BR><BR>1、指向文档类（CxxDoc）的指针：<BR>CxxDoc*pDoc = GetDocument();//文档指针<BR>则用pDoc-&gt;xxxx的方法可在视类中访问文档类中的变量和函数。<BR><BR>2、指向应用程序类（CxxApp）的指针：<BR>CxxApp*app = (CxxApp *)AfxGetApp();//应用程序指针<BR>用app-&gt;xxxx的方法可在文档类或视类中调用CxxApp中放置的数据了。<BR>我一般把文档和视公用的数据放在CxxApp类中，再用以上方法访问。<BR><BR>3、指向主框架（CMainFrame）的指针：<BR>CFrameWnd *pFrameWnd=GetParentFrame();//获取框架窗口指针<BR>用pFrameWnd-&gt;xxxx访问CWnd类的函数。<BR>这种方法多用于获取窗口的位置、大小等操作，用于视类。<BR><BR>4、指向某一控件的指针：<BR>如：CWnd *pEdit = GetDlgItem(IDC_EDIT1); //获取编辑控件指针<BR>IDC_EDIT1为<A name=2></A><B style="COLOR: black; BACKGROUND-COLOR: #99ff99">控件ID</B>号。<BR>这主要是为了能修改控件大小、位置，<A name=1></A><B style="COLOR: black; BACKGROUND-COLOR: #a0ffff">获取控件</B>风格等。<BR><BR>5、指向状态条的指针：<BR>CStatusBar* pStatus;//状态栏指针<BR>pStatus=(CStatusBar *)(app-&gt;m_pMainWnd-&gt;GetDescendantWindow(ID_VIEW_STATUS_BAR));<BR>app为上面的应用程序指针。<BR>这主要是为了更改状态栏中显示的内容。<BR><BR><BR><B>VC学习笔记10：状态栏：</B><BR><BR>1、在状态栏中显示提示：<BR>CxxApp*app = (CxxApp *)AfxGetApp();//应用程序指针<BR>CStatusBar* pStatus;//状态栏指针<BR>if(pStatus)<BR>{<BR>pStatus=(CStatusBar *)(app-&gt;m_pMainWnd-&gt;GetDescendantWindow(ID_VIEW_STATUS_BAR));<BR>pStatus-&gt;SetPaneText(0,str);//0为状态栏窗格号，str为显示的字符串<BR>}<BR><BR>2、在状态栏中增加窗格：<BR><BR>下例中增加了三个新窗格：<BR>(1)修改MainFrm.cpp：<BR><BR>static UINT indicators[] =<BR>{<BR>ID_SEPARATOR,// status line indicator<BR><BR>ID_SEPARATOR,//新增窗格1：放置总字节数<BR>ID_SEPARATOR,//新增窗格2：半角字数<BR>ID_SEPARATOR,//新增窗格3：全角字数<BR><BR>ID_INDICATOR_CAPS,<BR>ID_INDICATOR_NUM,<BR>ID_INDICATOR_SCRL,<BR>};<BR><BR>int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)<BR>{<BR>if (CFrameWnd::OnCreate(lpCreateStruct) == -1)<BR>return -1;<BR><BR>if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP<BR>| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||<BR>!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))<BR>{<BR>TRACE0("Failed to create toolbar\n");<BR>return -1;// fail to create<BR>}<BR><BR>if (!m_wndStatusBar.Create(this) ||<BR>!m_wndStatusBar.SetIndicators(indicators,<BR>sizeof(indicators)/sizeof(UINT)))<BR>{<BR>TRACE0("Failed to create status bar\n");<BR>return -1;// fail to create<BR>}<BR><BR>m_wndStatusBar.SetPaneInfo(1,ID_SEPARATOR,0,95); //设置新增窗格1的宽度<BR>m_wndStatusBar.SetPaneInfo(2,ID_SEPARATOR,0,100); //设置新增窗格2的宽度<BR>m_wndStatusBar.SetPaneInfo(3,ID_SEPARATOR,0,100); //设置新增窗格3的宽度<BR><BR>…………<BR>}<BR><BR>(2)在新窗格中显示内容<BR><BR>以下程序为视类中显示状态信息的部分，<BR>CStatusBar *pStatus=(CStatusBar *)AfxGetApp()-&gt;m_pMainWnd-&gt;GetDescendantWindow(ID_VIEW_STATUS_BAR);<BR>if(pStatus)<BR>{<BR>CString str;<BR>str.Format("字节数：%d",len)；<BR>pStatus-&gt;SetPaneText(1,str);//在窗格1显示内容<BR>str.Format("半角字符：%d",chnum);<BR>pStatus-&gt;SetPaneText(2,str);//在窗格2显示内容<BR>str.Format("全角字符：%d",hannum/2);<BR>pStatus-&gt;SetPaneText(3,str);//在窗格3显示内容<BR>}<BR><BR><BR><B>VC学习笔记11：设置程序窗口的初始大小：</B><BR><BR>在应用程序类（CxxAPP）的 InitInstance 函数中加入：<BR>m_pMainWnd-&gt;SetWindowPos(NULL,x,y,Width,Height,SWP_NOMOVE);<BR>Width为窗口宽度，Height为窗口高度<BR>SWP_NOMOVE表示忽略位置(x,y)。<BR><BR>如：<BR>BOOL CDzyApp::InitInstance()<BR>{<BR>AfxEnableControlContainer();<BR><BR>……<BR><BR>// The one and only window has been initialized, so show and update it.<BR>m_pMainWnd-&gt;SetWindowPos(NULL,0,0,750,555,SWP_NOMOVE);//设置窗口的初始大小为750*555<BR><BR>m_pMainWnd-&gt;ShowWindow(SW_SHOW);<BR>m_pMainWnd-&gt;UpdateWindow();<BR><BR>return TRUE;<BR>}<BR><BR><BR><B>VC学习笔记12：如何让窗口一启动就最大化?</B><BR><BR>方法一：<BR><BR>将应用程序类（CxxAPP）的 InitInstance 函数中的<BR><BR>m_pMainWnd-&gt;ShowWindow(SW_SHOW); 改为<BR>m_pMainWnd-&gt;ShowWindow(SW_SHOWMAXIMIZED); //让窗口一启动就最大化<BR><BR>例：<BR>BOOL CMyEditApp::InitInstance()<BR>{<BR>…………<BR><BR>m_pMainWnd-&gt;ShowWindow(SW_SHOWMAXIMIZED);<BR><BR>…………<BR>}<BR><BR>方法二：<BR><BR>在应用程序类（CxxAPP）的 InitInstance 函数中设定 m_nCmdShow的取值.<BR>m_nCmdShow=SW_SHOWMAXIMIZED; //最大化<BR>m_nCmdShow=SW_SHOWMINIMIZED; //最小化<BR>m_nCmdShow=SW_SHOWNORMAL; //正常方式<BR><BR>例：<BR>BOOL CMyEditApp::InitInstance()<BR>{<BR>AfxEnableControlContainer();<BR>m_nCmdShow=SW_SHOWMAXIMIZED; //最大化<BR>// Standard initialization<BR>// If you are not using these features and wish to reduce the size<BR>// of your final executable, you should remove from the following<BR>// the specific initialization routines you do not need.<BR><BR>#ifdef _AFXDLL<BR>Enable3dControls(); // Call this when using MFC in a shared DLL<BR>#else<BR>Enable3dControlsStatic(); // Call this when linking to MFC statically<BR>#endif<BR><BR>…………<BR>}<BR><BR><BR><B>VC学习笔记13：使窗口打开时处于屏幕正中：</B><BR><BR>在MainFrm.cpp文件的OnCreate函数中加入：<BR>CenterWindow( GetDesktopWindow() );<BR>即可。<BR><BR>如：<BR>int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)<BR>{<BR>if (CFrameWnd::OnCreate(lpCreateStruct) == -1)<BR>return -1;<BR>……<BR><BR>// TODO: Delete these three lines if you don't want the toolbar to<BR>// be dockable<BR>m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);<BR>EnableDocking(CBRS_ALIGN_ANY);<BR>DockControlBar(&amp;m_wndToolBar);<BR><BR>CenterWindow( GetDesktopWindow() ); //使窗口打开时处于屏幕正中<BR><BR>return 0;<BR>}<BR><BR><BR><B>VC学习笔记14：修改程序窗口标题：</B><BR><BR>窗口标题一般形式为：文档标题 - 程序标题<BR><BR>1、修改文档标题：<BR>文档标题是由工程中相应的文档类所控制的，因此我们可以在文档中利用SetTitle()函数来改变文档标题。<BR>在文档类的OnNewDocument()函数中加入语句：<BR>BOOL CWEditDoc::OnNewDocument()<BR>{<BR>if (!CDocument::OnNewDocument())<BR>return FALSE;<BR><BR>// TODO: add reinitialization code here<BR>// (SDI documents will reuse this document)<BR>SetTitle("未命名");//设置文档标题<BR><BR>return TRUE;<BR>}<BR><BR>2、修改程序标题：<BR>在MainFrm.cpp的PreCreateWindow()函数中加入：<BR>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&amp; cs)<BR>{<BR>if( !CFrameWnd::PreCreateWindow(cs) )<BR>return FALSE;<BR>// TODO: Modify the Window class or styles here by modifying<BR>//the CREATESTRUCT cs<BR>m_strTitle = _T("记事本");//设置程序标题<BR><BR>cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE<BR>| WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE;<BR><BR>return TRUE;<BR>}<BR>以上两条比较适合于窗口标题是固定值的情况，或用来设置初始时的窗口标题。若标题经常改变，可采用CWnd类的SetWindowText()函数。<BR><BR>3、修改整个标题：<BR>AfxGetMainWnd()-&gt;SetWindowText(m_Title);<BR>m_Title为新标题的字符串变量<BR><BR>一般把该语句放在应用程序类的 InitInstance 函数中。<BR><BR>例：<BR>BOOL CMyEditApp::InitInstance()<BR>{<BR>AfxEnableControlContainer();<BR><BR>…………<BR><BR>m_pMainWnd-&gt;ShowWindow(SW_SHOW);<BR>m_pMainWnd-&gt;UpdateWindow();<BR><BR>AfxGetMainWnd()-&gt;SetWindowText("未命名.txt - 记事本"); //修改标题<BR><BR>return TRUE;<BR>}<BR>该函数也可在视图类中随时修改标题。<img src ="http://www.cppblog.com/ivenher/aggbug/1130.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-15 14:53 <a href="http://www.cppblog.com/ivenher/articles/1130.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>托盘编程 </title><link>http://www.cppblog.com/ivenher/articles/1078.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 11 Nov 2005 06:03:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1078.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1078.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1078.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1078.html</trackback:ping><description><![CDATA[<TABLE align=left border=0>
<TBODY>
<TR>
<TD>
<SCRIPT language=javascript src="httP://www.chinaitpower.com/images/ad.js" charset=utf-8></SCRIPT>
</TD></TR></TBODY></TABLE>一、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;托盘简介<BR><BR>所谓的“托盘”，在Windows<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>界面中，指的就是下面任务条右侧，有<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>时间等等的标志的那一部分。在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>最小化或挂起时，但有不希望占据任务栏的时候，就可以把<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>放到托盘区。其实，托盘区的编程很简单，下面简要阐述一下子喽^_^<BR><BR>二、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;托盘编程相关函数<BR><BR>其实呢，把<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>放到托盘上的本质就是先在托盘区绘制一个图标，然后把<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>隐藏不见，再对托盘的图标进行消息处理，就可以了。<BR><BR>绘制图标以及确定图标所传送消息的函数只有一个，那就是——————<BR><BR>WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(<BR>&nbsp;&nbsp;&nbsp;&nbsp;DWORD dwMessage, <BR>&nbsp;&nbsp;&nbsp;&nbsp;PNOTIFYICONDATA pnid<BR>); <BR>这个函数呢，负责向<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>传递消息，以添加、修改或删除托盘区的图标。<BR><BR>她的返回值呢，是个布尔类型的。就是说，如果返回0，那就是成仁啦，非0才成功。<BR><BR>参数dwMessage 是表示这个函数的应用功能是哪一方面，是添加、删除，还是修改图标。如果是添加，则它的值为NIM_ADD；删除则是NIM_DELETE；而修改是NIM_MODIFY。<BR><BR>参数pnid就是具体的和<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>在托盘区的图标有关系的结构了。它的定义如下：<BR><BR>typedef struct _NOTIFYICONDATA { <BR>&nbsp;&nbsp;&nbsp;&nbsp;DWORD cbSize; <BR>&nbsp;&nbsp;&nbsp;&nbsp;HWND hWnd; <BR>&nbsp;&nbsp;&nbsp;&nbsp;UINT uID; <BR>&nbsp;&nbsp;&nbsp;&nbsp;UINT uFlags; <BR>&nbsp;&nbsp;&nbsp;&nbsp;UINT uCallbackMessage; <BR>&nbsp;&nbsp;&nbsp;&nbsp;HICON hIcon; <BR>&nbsp;&nbsp;&nbsp;&nbsp;char szTip[64]; <BR>} NOTIFYICONDATA, *PNOTIFYICONDATA; <BR><BR>下面就对该结构各个参数进行刨析：<BR><BR>cbSize : 结构的长度，用“位”来做单位。一般在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中，我们用(DWORD)sizeof(NOTIFYICONDATA) 给它赋值。<BR><BR>HWnd : 一个句柄，如果对托盘中的图标进行操作，相应的消息就传给这个句柄所代表的窗口。自然了，大多数情况下是this-&gt;m_hWnd喽。<BR><BR>uID : 在工程中定义的图标ID<BR><BR>uFlags : 这个成员标志着其他哪些成员的数据是有效的，分别为NIF_ICON, NIF_MESSAGE, NIF_TIP，分别代表着数据有效的成员是hIcon, uCallbackMessage, szTip。当然，三个值可以用“|”联系到一起。下面分别对涉及到的成员进行阐述<BR><BR>hIcon : 要增加，删除或修改的图标句柄。如果只知道个uID, 一般可能会用函数LoadIcon来得到句柄。例如LoadIcon ( AfxGetInstanceHandle() ,MAKEINTRESOURCE (IDR_MAINFRAME) )。<BR><BR>uCallbackMessage : 这在对托盘区的操作中，是比较重要的数据成员。这是个消息标志，当用鼠标对托盘区相应图标进行操作的时候，就会传递消息给Hwnd所代表的窗口。所以说，在uFlags中，一般都得标志它有效。这里一般都是自定义的消息。<BR><BR>szTip : 鼠标移动到托盘图标上时的提示文字。<BR><BR>三、&nbsp;&nbsp;&nbsp;&nbsp;托盘编程例子<BR><BR>有关托盘编程的基础知识呢，也就上面这些了。下面呢，我们就进入具体的实战演练阶段，举几个托盘编程的例子瞧瞧，加深理解。<BR><BR>1、&nbsp;&nbsp;将<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>最小化到<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>托盘区的函数toTray()。<BR><BR>void CTimeWakeDlg::toTray()<BR><BR>{<BR><BR>NOTIFYICONDATA nid;<BR><BR>nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);<BR><BR>nid.hWnd=this-&gt;m_hWnd;<BR><BR>nid.uID=IDR_MAINFRAME;<BR><BR>nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;<BR><BR>nid.uCallbackMessage=WM_SHOWTASK;//自定义的消息名称<BR><BR>nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));<BR><BR>strcpy(nid.szTip,"计划任务提醒");//信息提示条为“计划任务提醒”<BR><BR><BR><BR>Shell_NotifyIcon(NIM_ADD,&amp;nid);//在托盘区添加图标<BR><BR>ShowWindow(SW_HIDE);//隐藏主窗口<BR><BR>}<BR><BR>这是个很简单的函数，里面首先给NOTIFYICONDATA赋值，然后调用shell_NotifyIcon, 头一个参数是NIM_ADD，表示添加。然后用函数ShowWindow 隐藏主窗口，这样，就实现了将<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>最小化到<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>托盘区的任务了。<BR><BR>2、&nbsp;&nbsp;<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>已经最小化到托盘区了，但是呢，对托盘图标的操作如何进行呢？这就体现了结构NOTIFYICONDATA的成员uCallbackMessage 的作用了。它所提供的作用就是，当用户用鼠标点击托盘区的图标的时候（无论是左键还是右键），会向hWnd所代表的窗口传送消息，如果是上例，消息的名称就是WM_SHOWTASK。根据<A href="http://www.chinaitpower.com/Dev/Programme/VC/index.html" target=_blank>VC</A>的消息机制，对自定义消息增加消息响应函数。<BR><BR>在头<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>的//{{AFX_MSG和//}}AFX_MSG之间声明消息响应函数：<BR><BR>afx_msg LRESULT onShowTask(WPARAM wParam,LPARAM lParam);<BR><BR>然后在CPP<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>中添加消息映射。在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP 之间加入：<BR><BR>ON_MESSAGE(WM_SHOWTASK,onShowTask)将消息和消息响应函数映射起来。<BR><BR>然后就是在CPP<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>中加入函数onShowTask的实现了：<BR><BR>LRESULT CTimeWakeDlg::onShowTask(WPARAM wParam,LPARAM lParam)<BR><BR>//wParam接收的是图标的ID，而lParam接收的是鼠标的行为<BR><BR>{<BR><BR>if(wParam!=IDR_MAINFRAME)<BR><BR>return 1;<BR><BR>switch(lParam)<BR><BR>{<BR><BR>case WM_RBUTTONUP://右键起来时弹出快捷菜单，这里只有一个“关闭”<BR><BR>{<BR><BR>LPPOINT lpoint=new tagPOINT;<BR><BR>::GetCursorPos(lpoint);//得到鼠标位置<BR><BR>CMenu menu;<BR><BR>menu.CreatePopupMenu();//声明一个弹出式菜单<BR><BR>//增加菜单项“关闭”，点击则发送消息WM_DESTROY给主窗口（已<BR><BR>//隐藏），将<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>结束。<BR><BR>menu.AppendMenu(MF_STRING,WM_DESTROY,"关闭"); <BR><BR>//确定弹出式菜单的位置<BR><BR>menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint-&gt;x,lpoint-&gt;y,this);<BR><BR>//资源回收<BR><BR>HMENU hmenu=menu.Detach();<BR><BR>menu.DestroyMenu();<BR><BR>delete lpoint;<BR><BR>}<BR><BR>break;<BR><BR>case WM_LBUTTONDBLCLK://双击左键的处理<BR><BR>{<BR><BR>this-&gt;ShowWindow(SW_SHOW);//简单的显示主窗口完事儿<BR><BR>}<BR><BR>break;<BR><BR>}<BR><BR>return 0;<BR><BR>}<BR><BR><BR><BR>完了，就完了，没什么可再说的啦。<img src ="http://www.cppblog.com/ivenher/aggbug/1078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-11 14:03 <a href="http://www.cppblog.com/ivenher/articles/1078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows编程中的堆管理 </title><link>http://www.cppblog.com/ivenher/articles/1076.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 11 Nov 2005 05:45:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1076.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1076.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1076.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1076.html</trackback:ping><description><![CDATA[<TABLE align=left border=0>
<TBODY>
<TR>
<TD>
<SCRIPT language=javascript src="httP://www.chinaitpower.com/images/ad.js" charset=utf-8></SCRIPT>
</TD></TR></TBODY></TABLE>摘要： 本文主要对Windows内存管理中的堆管理技术进行讨论，并简要介绍了堆的创建、内存块的分配与再分配、堆的撤销以及new和delete操作符的使用等内容。<BR><BR>　　关键词： 堆；堆管理<BR>　　<B>1 引言</B><BR><BR>　　在大多数Windows应用<A href='http://dev.chinaitpower.com/<a%20href="http://www.chinaitpower.com/Dev/Programme/Java/index.html"%20target="_blank">java</a>/j2me/code/' target=_blank><A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>设计</A>中，都几乎不可避免的要对内存进行操作和管理。在进行大尺寸内存的动态分配时尤其显的重要。本文即主要对内存管理中的堆管理技术进行论述。<BR><BR>　　堆（Heap）实际是位于保留的虚拟地址空间中的一个区域。刚开始时，保留区域中的多数页面并没有被提交物理存储器。随着从堆中越来越多的进行内存分配，堆管理器将逐渐把更多的物理存储器提交给堆。堆的物理存储器从<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>页<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>中分配，在释放时有专门的堆管理器负责对已占用物理存储器的回收。堆管理也是Windows提供的一种内存管理机制。主要用来分配小的数据块。与Windows的其他两种内存管理机制虚拟内存和内存映射<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>相比，堆可以不必考虑诸如<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>的分配粒度和页面边界之类比较烦琐而又容易忽视的问题，可将注意力集中于对<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>功能代码的设计上。但是使用堆去分配、释放内存的速度要比其他两种机制慢的多，而且不具备直接控制物理存储器提交与回收的能力。<BR><BR>　　在进程刚启动时，<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>便在刚创建的进程虚拟地址空间中创建了一个堆，该堆即为进程的默认堆，缺省大小为1MB，该值允许在链接<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>时被更改。进程的默认堆是比较重要的，可供众多Windows函数使用。在使用时，<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>必须保证在规定的时间内，每此只有一个线程能够分配和释放默认堆中的内存块。虽然这种限制将会对访问速度产生一定的影响，但却可以保证进程中的多个线程在同时调用各种Windows函数时对默认堆的顺序访问。在进程中允许使用多个堆，进程中包括默认堆在内的每个堆都有一个堆句柄来标识。与自己创建的堆不同，进程默认堆的创建、销毁均由<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>来完成，而且其生命期早在进程开始执行之前就已经开始，虽然在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中可以通过GetProcessHeap（）函数得到进程的默认堆句柄，但却不允许调用HeapDestroy（）函数显式将其撤消。<BR><BR>　　<B>2 对动态创建堆的需求</B><BR><BR>　　前面曾提到，在进程中除了进程默认堆外，还可以在进程虚拟地址空间中动态创建一些独立的堆。至于在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>设计时究竟需不需要动态创建独立的堆可以从是否有保护组件的需要、是否能更加有效地对内存进行管理、是否有进行本地访问的需要、是否有减少线程同步开销的需要以及是否有迅速释放堆的需要等几个方面去考虑。<BR><BR>　　对于是否有保护组件的需要这一原则比较容易理解。在图1中，左边的图表示了一个链表（节点结构）组件和一个树（分支结构）组件共同使用一个堆的情况。在这种情况下，由于两组件数据在堆中的混合存放，如果节点3（属于链表组件）的后几个字节由于被错误改写，将有可能影响到位于其后的分支2（属于树组件）。这将致使树组件的相关代码在遍历其树时由于内存被破坏而无法进行。究其原因，树组件的内存是由于链表组建对其自身的错误操作而引起的。如果采用右图所示方式，将树组件和链表组件分别存放于一个独立的堆中，上述情况显然不会发生，错误将被局限于进行了错误操作的链表组件，而树组件由于存放在独立的堆中而受到了保护。<BR><BR><IMG hspace=3 src="http://www.chinaitpower.com/A-A-A/2005/07/17/20050717102544103477_1.jpg" align=center vspace=1 border=1><BR>图1 动态创建堆在保护组件中的作用<BR><BR>　　在上图中，如果链表组件的每个节点占用12个字节，每个树组件的分支占用16个字节如果这些长度不一的对象共用一个堆（左图），在左图中这些已经分配了内存的对象已占满了堆，如果其中有节点2和节点4释放，将会产生24个字节的碎片，如果试图在24个字节的空闲区间内分配一个16字节的分支对象，尽管要分配的字节数小于空闲字节数，但分配仍将失败。只有在堆栈中分配大小相同的对象才可以实行更加有效的内存管理。如果将树组件换成其他长度为12字节的组件，那么在释放一个对象后，另一个对象就可以恰好填充到此刚释放的对象空间中。<BR><BR>　　进行本地访问的需要也是一条比较重要的原则。<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>会经常在内存与<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>页<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>之间进行页面交换，但如果交换次数过多，<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>的运行性能就将受很大的影响。因此在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>设计时应尽量避免<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>频繁交换页面，如果将那些会被同时访问到的数据分配在相互靠近的位置上，将会减少<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>在内存和页<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>之间的页面交换频率。<BR><BR>　　线程同步开销指的是默认条件下以顺序方式运行的堆为保护数据在多个线程试图同时访问时不受破坏而必须执行额外代码所花费的开销。这种开销保证了堆对线程的安全性，因此是有必要的，但对于大量的堆分配操作，这种额外的开销将成为一个负担，并降低<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的运行性能。为避免这种额外的开销，可以在创建新堆时通知<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>只有单个线程对访问。此时堆对线程的安全性将有应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>来负责。<BR><BR>　　最后如果有迅速释放堆的需要，可将专用堆用于某些数据结构，并以整个堆去释放，而不再显式地释放在堆中分配的每一个内存块。对于大多数应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>，这样的处理将能以更快的速度运行。<BR><BR>
<SCRIPT>zmbbs=1;</SCRIPT>
<BR><BR>　　<B>3 创建堆</B><BR><BR>　　在进程中，如果需要可以在原有默认堆的基础上动态创建一个堆，可由HeapCreate（）函数完成：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>HANDLE HeapCreate(<BR>　DWORD flOptions,<BR>　DWORD dwInitialSize,<BR>　DWORD dwMaximumSize<BR>);</TD></TR></TBODY></TABLE><BR>　　其第一个参数flOptions指定了对新建堆的操作属性。该标志将会影响一些堆函数如HeapAlloc（）、HeapFree（）、HeapReAlloc（）和HeapSize（）等对新建堆的访问。其可能的取值为下列标志及其组合：<BR><BR>
<TABLE cellSpacing=0 width="100%" border=1>
<TBODY>
<TR>
<TD>属性标志</TD>
<TD>说明</TD></TR>
<TR>
<TD>HEAP_GENERATE_EXCEPTIONS</TD>
<TD>在遇到由于内存越界等而引起的函数失败时，由<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>抛出一个异常来指出此失败，而不是简单的返回NULL指针。</TD></TR>
<TR>
<TD>HEAP_NO_SERIALIZE </TD>
<TD>指明互斥现象不会出现</TD></TR></TBODY></TABLE><BR>　　参数dwInitialSize和dwMaximumSize分别为堆的初始大小和堆栈的最大尺寸。其中，dwInitialSize的值决定了最初提交给堆的字节数。如果设置的数值不是页面大小的整数倍，则将被圆整到邻近的页边界处。而dwMaximumSize则实际上是<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>能为堆保留的地址空间区域的最大字节数。如果该值为0，那么将创建一个可扩展的堆，堆的大小仅受可用内存的限制。如果应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>需要分配大的内存块，通常要将该参数设置为0。如果dwMaximumSize大于0，则该值限定了堆所能创建的最大值，HeapCreate（）同样也要将该值圆整到邻近的页边界，然后再在进程的虚拟地址空间为堆保留该大小的一块区域。在这种堆中分配的内存块大小不能超过0x7FFF8字节，任何试图分配更大内存块的行为将会失败，即使是设置的堆大小足以容纳该内存块。如果HeapCreate（）成功执行，将会返回一个标识新堆的句柄，并可供其他堆函数使用。<BR><BR>　　需要特别说明的是，在设置第一个参数时，对HEAP_NO_SERIALIZE的标志的使用要谨慎，一般应避免使用该标志。这是同后续将要进行的堆函数HeapAlloc（）的执行过程有关系的，在HeapAlloc（）试图从堆中分配一个内存块时，将执行下述几步操作：<BR><BR>　　1） 遍历分配的和释放的内存块的链接表<BR><BR>　　2） 搜寻一个空闲内存块的地址<BR><BR>　　3） 通过将空闲内存块标记为"已分配"来分配新内存块<BR><BR>　　4） 将新分配的内存块添加到内存块列表<BR><BR>　　如果这时有两个线程1、2试图同时从一个堆中分配内存块，那么线程1在执行了上面的1和2步后将得到空间内存块的地址。但是由于CPU对线程运行时间的分片，使得线程1在执行第3步操作前有可能被线程2抢走执行权并有机会去执行同样的1、2步操作，而且由于先执行的线程1并没有执行到第3步，因此线程2会搜寻到同一个空闲内存块的地址，并将其标记为已分配。而线程1在恢复运行后并不能知晓该内存块已被线程2标记过，因此会出现两个线程军认为其分配的是空闲的内存块，并更新各自的联接表。显然，象这种两个线程拥有完全相同内存块地址的错误是非常严重而又是难以发现的。<BR><BR>　　由于只有在多个线程同时进行操作时才有可能出现上述问题，一种简单的解决的办法就是不使用HEAP_NO_SERIALIZE标志而只允许单个线程独占地对堆及其联接表拥有访问权。如果一定要使用此标志，为了安全起见，必须确保进程为单线程的或是在进程中使用了多线程，但只有单个线程对堆进行访问。再就是使用了多线程，也有多个线程对堆进行了访问，但这些线程通过使用某种线程同步手段。如果可以确保以上几条中的一条成立，也是可以安全使用HEAP_NO_SERIALIZE标志的，而且还将拥有快的访问速度。如果不能肯定上述条件是否满足，建议不使用此标志而以顺序的方式访问堆，虽然线程速度会因此而下降但却可以确保堆及其中数据的不被破坏。<BR><BR>　　<B>4 从堆中分配内存块<BR></B><BR>　　在成功创建一个堆后，可以调用HeapAlloc（）函数从堆中分配内存块。在此，除了可以从用HeapCreate（）创建的动态堆中分配内存块，也可以直接从进程的默认堆中分配内存块。下面先给出HeapCreate（）的函数原型：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>LPVOID HeapAlloc(<BR>　HANDLE hHeap,<BR>　DWORD dwFlags,<BR>　DWORD dwBytes<BR>);</TD></TR></TBODY></TABLE><BR>　　其中，参数hHeap为要分配的内存块来自的堆的句柄，可以是从HeapCreate（）创建的动态堆句柄也可以是由GetProcessHeap（）得到的默认堆句柄。参数dwFlags指定了影响堆分配的各个标志。该标志将覆盖在调用HeapCreate（）时所指定的相应标志，可能的取值为：<BR><BR>
<TABLE cellSpacing=0 width="100%" border=1>
<TBODY>
<TR>
<TD>标志 </TD>
<TD>说明</TD></TR>
<TR>
<TD>HEAP_GENERATE_EXCEPTIONS</TD>
<TD>该标志指定在进行诸如内存越界操作等情况时将抛出一个异常而不是简单的返回NULL指针</TD></TR>
<TR>
<TD>HEAP_NO_SERIALIZE</TD>
<TD>强制对HeapAlloc（）的调用将与访问同一个堆的其他线程不按照顺序进行</TD></TR>
<TR>
<TD>HEAP_ZERO_MEMORY</TD>
<TD>如果使用了该标志，新分配内存的内容将被初始化为0</TD></TR></TBODY></TABLE><BR>　　最后一个参数dwBytes设定了要从堆中分配的内存块的大小。如果HeapAlloc（）执行成功，将会返回从堆中分配的内存块的地址。如果由于内存不足或是其他一些原因而引起HeapAlloc（）函数的执行失败，将会引发异常。通过异常标志可以得到引起内存分配失败的原因：如果为STATUS_NO_MEMORY则表明是由于内存不足引起的；如果是STATUS_ACCESS_VIOLATION则表示是由于堆被破坏或函数参数不正确而引起分配内存块的尝试失败。以上异常只有在指定了HEAP_GENERATE_EXCEPTIONS标志时才会发生，如果没有指定此标志，在出现类似错误时HeapAlloc（）函数只是简单的返回NULL指针。<BR><BR>　　在设置dwFlags参数时，如果先前用HeapCreate（）创建堆时曾指定过HEAP_GENERATE_EXCEPTIONS标志，就不必再去设置HEAP_GENERATE_EXCEPTIONS标志了，因为HEAP_GENERATE_EXCEPTIONS标志已经通知堆在不能分配内存块时将会引发异常。另外，对HEAP_NO_SERIALIZE标志的设置应慎重，与在HeapCreate（）函数中使用HEAP_NO_SERIALIZE标志类似，如果在同一时间有其他线程使用同一个堆，那么该堆将会被破坏。如果是在进程默认堆中进行内存块的分配则要绝对禁用此标志。<BR><BR>　　在使用堆函数HeapAlloc（）时要注意：堆在内存管理中的使用主要是用来分配一些较小的数据块，如果要分配的内存块在1MB左右，那么就不要再使用堆来管理内存了，而应选择虚拟内存的内存管理机制。<BR><BR>
<SCRIPT>zmbbs=1;</SCRIPT>
<BR>　　<B>5 再分配内存块</B><BR><BR>　　在<A href='http://dev.chinaitpower.com/<a%20href="http://www.chinaitpower.com/Dev/Programme/Java/index.html"%20target="_blank">java</a>/j2me/code/' target=_blank><A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>设计</A>时经常会由于开始时预见不足而造成在堆中分配的内存块大小的不合适（多数情况是开始时分配的内存较小，而后来实际需要更多的数据复制到内存块中去）这就需要在分配了内存块后再根据需要调整其大小。堆函数HeapReAlloc（）将完成这一功能，其函数原型为：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>LPVOID HeapReAlloc(<BR>　HANDLE hHeap, <BR>　DWORD dwFlags,<BR>　LPVOID lpMem, <BR>　DWORD dwBytes <BR>);</TD></TR></TBODY></TABLE><BR>　　其中，参数hHeap为包含要调整其大小的内存块的堆的句柄。dwFlags参数指定了在更改内存块大小时HeapReAlloc（）函数所使用的标志。其可能的取值为HEAP_GENERATE_EXCEPTIONS、HEAP_NO_SERIALIZE、HEAP_REALLOC_IN_PLACE_ONLY和HEAP_ZERO_MEMORY，其中前两个标志的作用与在HeapAlloc（）中的作用相同。HEAP_REALLOC_IN_PLACE_ONLY标志在内存块被加大时不移动堆中的内存块，在没有设置此标志的情况下如果对内存进行增大，那么HeapReAlloc（）函数将有可能将原内存块移动到一个新的地址。显然，在设置了该标志禁止内存快首地址进行调整时，将有可能出现没有足够的内存供试图增大的内存块使用，对于这种情况，函数对内存块增大调整的操作是失败的，内存块将仍保留原有的大小和位置。HEAP_ZERO_MEMORY标志的用处则略有不同，如果内存快经过调整比以前大，那么新增加的那部分内存将被初始化为0；如果经过调整内存块缩小了，那么该标志将不起任何作用。<BR><BR>　　函数的最后两个参数lpMem和dwBytes分别为指向再分配内存块的指针和再分配的字节数。如果函数成功执行，将返回新的改变了大小的内存块的地址。如果在调用时使用了HEAP_REALLOC_IN_PLACE_ONLY标志，那么返回的地址将与原内存块地址相同。如果因为内存不足等原因而引起函数的执行失败，函数将返回一个NULL指针。但是HeapReAlloc（）的执行失败并不会影响原内存块，它将保持原来的大小和位置继续存在。可以通过HeapSize（）函数来检索内存块的实际大小。<BR><BR>　　<B>6 释放堆内存、撤消堆</B><BR><BR>　　在不再需要使用堆中的内存块时，可以通过HeapFree（）将其予以释放。该函数结构比较简单，只含有三个参数：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>BOOL HeapFree(<BR>　HANDLE hHeap,<BR>　DWORD dwFlags, <BR>　LPVOID lpMem<BR>);</TD></TR></TBODY></TABLE><BR>　　其中，hHeap为要包含要释放内存块的堆的句柄；参数dwFlags为堆栈的释放选项可以是0，也可以是HEAP_NO_SERIALIZE；最后的参数lpMem为指向内存块的指针。如果函数成功执行，将释放指定的内存块，并返回TRUE。该函数的主要作用是可以用来帮助堆管理器回收某些不使用的物理存储器以腾出更多的空闲空间，但是并不能保证一定会成功。<BR><BR>　　最后，在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>退出前或是应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>不再需要其创建的堆了，可以调用HeapDestory（）函数将其销毁。该函数只包含一个参数--待销毁的堆的句柄。HeapDestory（）的成功执行将可以释放堆中包含的所有内存块，也可将堆占用的物理存储器和保留的地址空间区域全部重新返回给<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>并返回TRUE。该函数只对由HeapCreate（）显式创建的堆起作用，而不能销毁进程的默认堆，如果强行将由GetProcessHeap（）得到的默认堆的句柄作为参数去调用HeapDestory（），<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>将会忽略对该函数的调用。<BR><BR>
<SCRIPT>zmbbs=1;</SCRIPT>
<BR>　　<B>7 对new与delete操作符的重载</B><BR><BR>　　new与delete内存空间动态分配操作符是C++中使用堆进行内存管理的一种常用方式，在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>运行过程中可以根据需要随时通过这两个操作符建立或删除堆对象。new操作符将在堆中分配一个足够大小的内存块以存放指定类型的对象，如果每次构造的对象类型不同，则需要按最大对象所占用的空间来进行分配。new操作符在成功执行后将返回一个类型与new所分配对象相匹配的指针，如果不匹配则要对其进行强制类型转换，否则将会编译出错。在不再需要这个对象的时候，必须显式调用delete操作符来释放此空间。这一点是非常重要的，如果在预分配的缓冲里构造另一个对象之前或者在释放缓冲之前没有显式调用delete操作符，那么<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>将产生不可预料的后果。在使用delete操作符时，应注意以下几点： <BR><BR>　　1） 它必须使用于由运算符new返回的指针<BR><BR>　　2） 该操作符也适用于NULL指针<BR><BR>　　3） 指针名前只用一对方括号符，并且不管所删除数组的维数，忽略方括号内的任何数字<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>class CVMShow{<BR>　private:<BR>　　static HANDLE m_sHeap;<BR>　　static int m_sAllocedInHeap;<BR>　public:<BR>　　LPVOID operator new(size_t size);<BR>　　void operator delete(LPVOID pVoid);<BR>}<BR><BR>……<BR>HANDLE m_sHeap = NULL;<BR>int m_sAllocedInHeap = 0;<BR>LPVOID CVMShow::operator new(size_t size)<BR>{<BR>　if (m_sHeap == NULL)<BR>　　m_sHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0, 0);<BR>　　LPVOID pVoid = HeapAlloc(m_sHeap, 0, size);<BR>　　if (pVoid == NULL)<BR>　　　return NULL;<BR>　　　m_sAllocedInHeap++;<BR>　　return pVoid;<BR>}<BR>void CVMShow::operator delete(LPVOID pVoid)<BR>{<BR>　if (HeapFree(m_sHeap, 0, pVoid))<BR>　　m_sAllocedInHeap--;<BR>　　if (m_sAllocedInHeap == 0)<BR>　　{<BR>　　　if (HeapDestory(m_sHeap))<BR>　　　　m_sHeap = NULL;<BR>　　}<BR>}<BR></TD></TR></TBODY></TABLE><BR>　　在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中除了直接用上述方法使用new和delete来建立和删除堆对象外，还可以通过为C++类重载new和delete操作符来方便地利用堆栈函数。上面的代码对它们进行了简单的重载，并通过静态变量m_sHeap和m_sAllocedInHeap在类CVMShow的所有实例间共享唯一的堆句柄（因为在这里CVMShow类的所有实例都是在同一个堆中进行内存分配的）和已分配类对象的计数。这两个静态变量在代码开始执行时被分别初始化为NULL指针和0计数。<BR><BR>　　重载的new操作符在第一次被调用时，由于静态变量m_sHeap为NULL标志着堆尚未创建，就通过HeapCreate（）函数创建一个堆并返回堆句柄到m_sHeap。随后根据入口参数size所指定的大小在堆中分配内存，同时已分配内存块计数器m_sAllocedInHeap累加。在该操作符的以后调用过程中，由于堆已经创建，故不再创建堆，而是直接在堆中分配指定大小的内存块并对已分配的内存块个数进行计数。<BR><BR>　　在CVMShow类对象不再被应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>所使用时，需要将其撤消，由重载的delete操作符完成此工作。delete操作符只接受一个LPVOID型参数，即被删除对象的地址。该函数在执行时首先调用HeapFree（）函数将指定的已分配内存的对象释放并对已分配内存计数递减1。如果该计数不为零则表明当前堆中的内存块没有全部释放，堆暂时不予撤消。如果m_sAllocedInHeap计数减到0，则堆中已释放完所有的CVMShow对象，可以调用HeapDestory（）函数将堆销毁，并将堆句柄m_sHeap设置为NULL指针。这里在撤消堆后将堆句柄设置为NULL指针的操作是完全必要的。如果不执行该操作，当<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>再次调用new操作符去分配一个CVMShow类对象时将会认为堆是存在的而会试图在已撤消的堆中去分配内存，显然将会导致失败。<BR><BR>　　象CVMShow这样设计的类通过对new和delete操作符的重载，并且在一个堆中为所有的CVMShow类对象进行分配，可以节省在为每一个类都创建堆的分配开销与内存。这样的处理还可以让每一个类都拥有属于自己的堆，并且允许派生类对其共享，这在<A href='http://dev.chinaitpower.com/<a%20href="http://www.chinaitpower.com/Dev/Programme/Java/index.html"%20target="_blank">java</a>/j2me/code/' target=_blank><A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>设计</A>中也是比较好的一种处理方法。<BR><BR>　　<B>8 小结</B><BR><BR>　　在使用堆时有时会造成<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>运行速度的减慢，通常是由以下原因造成的：分配操作造成的速度减慢；释放操作造成的速度减慢；堆竞争造成的速度减慢；堆破坏造成的速度减慢；频繁的分配和重分配造成的速度减慢等。其中，竞争是在分配和释放操作中导致速度减慢的问题。基于上述原因，建议不要在<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中过于频繁的使用堆。文中所述代码均在Windows 2000 Professional下由Microsoft Visual C++ 6.0编译通过。<BR>
<SCRIPT>zmbbs=1;</SCRIPT><img src ="http://www.cppblog.com/ivenher/aggbug/1076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-11 13:45 <a href="http://www.cppblog.com/ivenher/articles/1076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Win32编程基础知识 </title><link>http://www.cppblog.com/ivenher/articles/1075.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 11 Nov 2005 05:44:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1075.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1075.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1075.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1075.html</trackback:ping><description><![CDATA[<BR><BR>　　尽管Windows应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>千变万化，令人眼花缭乱，但，消息机制和窗口过程却始终它们的基础，掌握了这两项技术，也就相当于把握住了问题的关键。<BR><BR>　　如果你以前是C<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>员或是MFC的忠实用户，只要你学习过C语言的语法，自己亲手编过一些简短的C<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>，理解以下的Win32编程基础也不是一件困难的事。<BR><BR>　　<B>一个最简单的Win32<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A></B> <BR><BR>　　在以前的C语言编程中，一个最简单的<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>可以只有两行。<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>void main(void)<BR><BR>{ printf "Hello World!"; } </TD></TR></TBODY></TABLE><BR>　　而要实现同样功能的Windows<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>却最少也要写几十行，这并不是说明Windows应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>效率低下，难于掌握，只是说明<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>在Windows环境下有更丰富的内涵。Windows<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的效率其实不低，在所有的Windows应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中，都有一个<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>初始化的过程，这得用上几十条语句，这段初始化的代码对于任何Windows应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>而言，都是大同小异的。下面以一个实现最简单功能的<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>EasyWin为例，说明Windows<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的基本框架。<BR><BR>　　打开Visual C++ 6.0。 <BR><BR>　　选择File菜单的New，在出现的对话框中，选择Projects栏目（新建工程），并点取其下的Win32 Application项，表示使用Win32环境创建应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>。先在Locatin（路径）中填入“c:\”，然后在Project Name（项目名称）中填入“EasyWin”，其它按照缺省设置）。单击OK按钮。<BR><BR>　　再次选择File菜单的New，在出现的对话框中，选择Files栏目（新建<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>），并点取其下的C++ Source File项，表示新建一个C++源<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>。在右边的File栏中输入“EasyWin”，最后确定让Add to project检查框打上勾 ）。单击OK按钮。 <BR><BR><BR><BR>　　在EasyWin.cpp<A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>中输入以下源<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>代码。 　<BR>　<BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>//*******************************************************************<BR>// 工程：easywin<BR>// <A href="http://www.chinaitpower.com/Soft/Tools/File/index.html" target=_blank>文件</A>：easywin.cpp<BR>// 内容：一个基本的Win32<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>//*******************************************************************<BR><BR>#include &lt;windows.h&gt;<BR><BR>#include &lt;windowsx.h&gt;<BR><BR>//函数声明<BR><BR>BOOL InitWindow( HINSTANCE hInstance, int nCmdShow );<BR><BR>LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );<BR><BR>//*******************************************************************<BR><BR>//函数：WinMain()<BR><BR>//功能：Win32应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>入口函数。创建主窗口，处理消息循环<BR><BR>//*******************************************************************<BR><BR>int PASCAL WinMain( HINSTANCE hInstance, //当前实例句柄<BR><BR>HINSTANCE hPrevInstance, //前一个实例句柄<BR><BR>LPSTR lpCmdLine, //命令行<A href="http://www.chinaitpower.com/Dev/Programme/VC/Str/index.html" target=_blank>字符</A><BR><BR>int nCmdShow) //窗口显示方式<BR><BR>{<BR><BR>MSG msg;<BR><BR>//创建主窗口<BR><BR>if ( !InitWindow( hInstance, nCmdShow ) )<BR><BR>return FALSE;<BR><BR>//进入消息循环：<BR><BR>//从该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的消息队列中检取消息，送到消息处理过程，<BR><BR>//当检取到WM_QUIT消息时，退出消息循环。<BR><BR>while (GetMessage(&amp;msg, NULL, 0, 0))<BR><BR>{<BR><BR>TranslateMessage(&amp;msg);<BR><BR>DispatchMessage(&amp;msg);<BR><BR>}<BR><BR>//<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>结束<BR><BR>return msg.wParam;<BR><BR>}<BR><BR>//******************************************************************<BR><BR>//函数：InitWindow()<BR><BR>//功能：创建窗口。<BR><BR>//******************************************************************<BR><BR>static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )<BR><BR>{<BR><BR>HWND hwnd; //窗口句柄<BR><BR>WNDCLASS wc; //窗口类结构<BR><BR>//填充窗口类结构<BR><BR>wc.style = CS_VREDRAW | CS_HREDRAW;<BR><BR>wc.lpfnWndProc = (WNDPROC)WinProc;<BR><BR>wc.cbClsExtra = 0;<BR><BR>wc.cbWndExtra = 0;<BR><BR>wc.hInstance = hInstance;<BR><BR>wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );<BR><BR>wc.hCursor = LoadCursor( NULL, IDC_ARROW );<BR><BR>wc.hbrBackground = GetStockObject(WHITE_BRUSH);<BR><BR>wc.lpszMenuName = NULL;<BR><BR>wc.lpszClassName = "EasyWin";<BR><BR>//注册窗口类<BR><BR>RegisterClass( &amp;wc );<BR><BR>　<BR><BR>//创建主窗口<BR><BR>hwnd = CreateWindow(<BR><BR>"EasyWin", //窗口类名称<BR><BR>"一个基本的Win32<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>", //窗口标题<BR><BR>WS_OVERLAPPEDWINDOW, //窗口风格，定义为普通型<BR><BR>100, //窗口位置的x坐标<BR><BR>100, //窗口位置的y坐标<BR><BR>400, //窗口的宽度<BR><BR>300, //窗口的高度<BR><BR>NULL, //父窗口句柄<BR><BR>NULL, //菜单句柄<BR><BR>hInstance, //应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>实例句柄<BR><BR>NULL ); //窗口创建数据指针<BR><BR>if( !hwnd ) return FALSE;<BR><BR>//显示并更新窗口<BR><BR>ShowWindow( hwnd, nCmdShow );<BR><BR>UpdateWindow( hwnd );<BR><BR>return TRUE;<BR><BR>}<BR><BR>//******************************************************************<BR><BR>//函数：WinProc()<BR><BR>//功能：处理主窗口消息<BR><BR>//******************************************************************<BR><BR>LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )<BR><BR>{<BR><BR>switch( message )<BR><BR>{<BR><BR>case WM_KEYDOWN://击键消息<BR><BR>switch( wParam )<BR><BR>{<BR><BR>case VK_ESCAPE:<BR><BR>MessageBox(hWnd,"ESC键按下了!","Keyboard",MB_OK);<BR><BR>break;<BR><BR>}<BR><BR>break;<BR><BR>case WM_RBUTTONDOWN://鼠标消息<BR><BR>{<BR><BR>MessageBox(hWnd,"鼠标右键按下了!","Mouse",MB_OK);<BR><BR>break;<BR><BR>}<BR><BR>case WM_PAINT://窗口重画消息<BR><BR>{<BR><BR>char hello[]="你好，我是EasyWin !";<BR><BR>HDC hdc;<BR><BR>PAINTSTRUCT ps;<BR><BR>hdc=BeginPaint( hWnd,&amp;ps ); //取得设备环境句柄<BR><BR>SetTextColor(hdc, RGB(0,0,255)); //设置文字颜色<BR><BR>TextOut( hdc, 20, 10, hello, strlen(hello) );//输出文字<BR><BR>EndPaint( hWnd, &amp;ps ); //释放资源<BR><BR>break;<BR><BR>}<BR><BR>case WM_DESTROY://退出消息<BR><BR>PostQuitMessage( 0 );//调用退出函数<BR><BR>break;<BR><BR>}<BR><BR>//调用缺省消息处理过程<BR><BR>return DefWindowProc(hWnd, message, wParam, lParam);<BR><BR>}</TD></TR></TBODY></TABLE><BR>　　<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>输入完毕，即可编译执行。在窗口中击鼠标键或按ESC键时，会弹出一个对话框以表示你的操作。<BR><BR>　　其实，这个<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>可以看成是所有Win32应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的框架，在以后所有的<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中，你会发现它们都是在这个<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的基础之上再添加代码。<BR><BR><BR>　　<B>WinMain()函数 </B><BR>　<BR>　　WinMain()函数是应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>开始执行时的入口点，通常也是应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>结束任务退出时的出口点。它与DOS<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的main()函数起同样的作用，有一点不同的是，WinMain()函数必须带有四个参数，它们是<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>传递给它的。WinMain()函数的原型如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>int PASCAL WinMain( HINSTANCE hInstance, //当前实例句柄<BR><BR>HINSTANCE hPrevInstance, //前一个实例句柄<BR><BR>LPSTR lpCmdLine, //命令行<A href="http://www.chinaitpower.com/Dev/Programme/VC/Str/index.html" target=_blank>字符</A><BR><BR>int nCmdShow) //窗口显示方式 </TD></TR></TBODY></TABLE><BR>　　第一个参数hInstance，是标识该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>当前的实例的句柄。它是HINSTANCE类型，HINSTANCE是Handle of Instance的缩写，表示实例的句柄。hInstance是一个很关键的数据，它唯一的代表该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>，在后面初始化<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>主窗口的过程中需要用到这个参数。<BR><BR>　　这里有两个概念，一个是实例，一个是句柄。实例代表的是应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>执行的整个过程和方法，一个应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>如果没有被执行，只是存在于磁盘上，那么就说它是没有被实例化的；只要一执行，则说该<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的一个实例在运行。句柄，顾名思义，指的是一个对象的把柄。在Windows中，有各种各样的句柄，它们都是32位的指针变量，用来指向该对象所占据的内存区。句柄的使用，可以极大的方便Windows管理其内存中的各种对象。 <BR><BR>　　第二个参数是hPrevInstance，它是用来标识该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的前一个实例句柄。对于基于Win32的应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>来说，这个参数总是NULL。这是因为在Win95操作<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>中，应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的每个实例都有各自独立的地址空间，即使同一个应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>被执行了两次，在内存中也会为它们的每一个实例分配新的内存空间，所以一个应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>被执行后，不会有前一个实例存在的可能。也就是说，hPrevInstance这个参数是完全没有必要的，只是为了提供与16位Windows的应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>形式上的兼容性，才保留了这个参数。在以前的16位Windows环境下（如Windows3.2），hPrevInstance用来标识与hInstance相关的应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的前一个句柄。<BR><BR>　　第三个参数是lpCmdLine，是指向应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>命令行参数<A href="http://www.chinaitpower.com/Dev/Programme/VC/Str/index.html" target=_blank>字符</A>串的指针。如在Win95的“开始”菜单中单击“运行”，输入“easywin hello”，则此参数指向的<A href="http://www.chinaitpower.com/Dev/Programme/VC/Str/index.html" target=_blank>字符</A>串为“hello”。<BR><BR>　　最后一个参数是nCmdShow，是一个用来指定窗口显示方式的整数。这个整数值可以是SW_SHOW、SW_HIDE、SW_SHOWMAXIMIZED、SW_SHOWMINIMIZED等，关于这些值的含义，将在下一节说明。<BR><BR><BR>　　<B>注册窗口类 </B><BR><BR>　　一个应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>可以有许多窗口，但只有一个是主窗口，它是与该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的实例句柄唯一关联的。上面的例程中，创建主窗口的函数是InitWindow()。 <BR><BR>　　通常要对填充一个窗口类结构WNDCLASS，然后调用RegisterClass()对该窗口类进行注册。每个窗口都有一些基本的属性，如窗口边框、窗口标题栏文字、窗口大小和位置、鼠标、背景色、处理窗口消息函数的名称等等。注册的过程也就是将这些属性告诉<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>，然后再调用CreateWindow()函数创建出窗口。这也就象你去裁缝店订做一件衣服，先要告诉店老板你的身材尺寸、布料颜色、以及你想要的款式，然后他才能为你做出一件让你满意的衣服。<BR><BR>　　在<A href="http://www.chinaitpower.com/Dev/Programme/VC/index.html" target=_blank>VC</A>的帮助中，可以看到WNDCLASS结构是这样定义的：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>typedef struct _WNDCLASS {<BR><BR>UINT style; //窗口的风格*<BR><BR>WNDPROC lpfnWndProc; //指定窗口的消息处理函数的远指针*<BR><BR>int cbClsExtra; //指定分配给窗口类结构之后的额外字节数*<BR><BR>int cbWndExtra; //指定分配给窗口实例之后的额外字节数<BR><BR>HANDLE hInstance; //指定窗口过程所对应的实例句柄*<BR><BR>HICON hIcon; //指定窗口的图标<BR><BR>HCURSOR hCursor; //指定窗口的鼠标<BR><BR>HBRUSH hbrBackground; //指定窗口的背景画刷<BR><BR>LPCTSTR lpszMenuName; //窗口的菜单资源名称<BR><BR>LPCTSTR lpszClassName; //该窗口类的名称*<BR><BR>} WNDCLASS;</TD></TR></TBODY></TABLE><BR>　　在Win95和WinNT的具有新界面特性的<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>中，为了支持新的窗口界面特性，还有一种扩展的窗口类型WNDCLASSEX，它的定义如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>typedef struct _WNDCLASSEX {<BR><BR>UINT cbSize; //指定WNDCLASSEX结构的大小<BR><BR>UINT style; <BR><BR>WNDPROC lpfnWndProc; <BR><BR>int cbClsExtra;<BR><BR>int cbWndExtra;<BR><BR>HANDLE hInstance; <BR><BR>HICON hIcon; <BR><BR>HCURSOR hCursor;<BR><BR>HBRUSH hbrBackground; <BR><BR>LPCTSTR lpszMenuName; <BR><BR>LPCTSTR lpszClassName;<BR><BR>HICON hIconSm; //窗口的小图标<BR><BR>} WNDCLASSEX;</TD></TR></TBODY></TABLE><BR>　　WNDCLASS和WNDCLASSEX这两个结构基本上是一致的，只是WNDCLASSEX结构中多了cbSize和hIconSm这两个成员。WNDCLASS结构的各成员中，其注释后打了星号的表示该项应特别注意。<BR><BR>　　WNDCLASS结构的第一个成员style表示窗口类的风格，它往往是由一些基本的风格通过位的“或”操作（操作符位“|”）组合而成。下表列出了一些常用的基本窗口风格：<BR><BR>
<TABLE cellSpacing=0 width="91%" border=1>
<TBODY>
<TR>
<TD>风格</TD>
<TD>含义 </TD></TR>
<TR>
<TD>CS_HREDRAW</TD>
<TD>如果窗口客户区宽度发生改变，重绘整个窗口 </TD></TR>
<TR>
<TD>CS_VREDRAW</TD>
<TD>如果窗口客户区高度发生改变，重绘整个窗口</TD></TR>
<TR>
<TD>CS_DBLCLKS</TD>
<TD>能感受用户在窗口中的双击消息 </TD></TR>
<TR>
<TD>CS_NOCLOSE</TD>
<TD>禁用<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>菜单中的“关闭”命令 </TD></TR>
<TR>
<TD>CS_OWNDC</TD>
<TD>为该窗口类的各窗口分配各自独立的设备环境 </TD></TR>
<TR>
<TD>CS_CLASSDC</TD>
<TD>为该窗口类的各窗口分配一个共享的设备环境 </TD></TR>
<TR>
<TD>CS_PARENTDC</TD>
<TD>指定子窗口继承其父窗口的设备环境</TD></TR>
<TR>
<TD>CS_SAVEBITS</TD>
<TD>把被窗口遮掩的屏幕图象部分作为位图保存起来。当该窗口被移动时，Windows使用被保存的位图来重建屏幕图象 </TD></TR></TBODY></TABLE><BR>　　在EasyWin应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中，是按如下方式对WNDCLASS结构进行填充和注册的：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>wc.style = CS_VREDRAW | CS_HREDRAW;<BR><BR>wc.lpfnWndProc = (WNDPROC)WinProc;<BR><BR>wc.cbClsExtra = 0;<BR><BR>wc.cbWndExtra = 0;<BR><BR>wc.hInstance = hInstance;<BR><BR>wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );<BR><BR>wc.hCursor = LoadCursor( NULL, IDC_ARROW );<BR><BR>wc.hbrBackground = GetStockObject(WHITE_BRUSH);<BR><BR>wc.lpszMenuName = NULL;<BR><BR>wc.lpszClassName = "EasyWin"; </TD></TR></TBODY></TABLE><BR>　　可以看到，wc.style被设为CS_VREDRAW | CS_HREDRAW，表示只要窗口的高度或宽度发生变化，都会重画整个窗口。<BR><BR>　　第二个成员lpfnWndProc的值为(WNDPROC)WinProc。表明该窗口类的消息处理函数是WinProc()函数。这里，要指定窗口的消息处理函数的远指针，输入消息处理函数的函数名称即可，必要时应该进行强制类型转换，将其转换成WNDPROC型。<BR><BR>　　接下来的cbClsExtra和wc.cbWndExtra在大多数情况下都会设为0。<BR><BR>　　然后的hInstance成员，给它的值是由WinMain()传来的应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的实例句柄，表明该窗口与该实例是相关联的。事实上，只要是注册窗口类，该成员的值始终是该<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的实例句柄，你应该象背书一样记住它。<BR><BR>　　下面的hIcon，是让你给这个窗口指定一个图标，调用 LoadIcon( hInstance, IDI_APPLICATION )，可以调用<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>内部预先定义好的标志符为IDC_APPLICATION的图标作为该窗口的图标。<BR><BR>　　同样，调用LoadCursor( NULL, IDC_ARROW )为该窗口调用<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>内部预先定义好的箭头型鼠标。<BR><BR>　　hbrBackground成员用来定义窗口的背景画刷颜色，也就是该窗口的背景色。调用GetStockObject(WHITE_BRUSH)可以获得<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>内部预先定义好的白色画刷作为窗口的背景色。<BR><BR>　　上面的LoadIcon()、LoadCursor()、GetStockObject()都是Windows的API函数，它们的用法可以参看<A href="http://www.chinaitpower.com/Dev/Programme/VC/index.html" target=_blank>VC</A>的帮助，这里就不多介绍了。<BR><BR>　　lpszMenuName成员的值我们给它NULL，表示该窗口将没有菜单。如果你想让你的窗口拥有菜单，就把lpszMenuName成员赋值为标志菜单资源的<A href="http://www.chinaitpower.com/Dev/Programme/VC/Str/index.html" target=_blank>字符</A>串。<BR><BR>　　WNDCLASS结构的最后一个成员lpszClassName是让你给这个窗口类起一个唯一的名称，因为Windows操作<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>中有许许多多的窗口类，必须用一个独一无二的名称来代表它们。通常，你可以用你的<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>名来命名这个窗口类的名称。这个名称将在创建窗口的CreateWindow()函数中用到。<BR><BR>　　填充完毕后，对于WNDCLASS结构，调用RegisterClass()函数进行注册；对于WNDCLASSEX结构，调用RegisterClassEx()函数进行注册，它们的原型分别如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); <BR><BR>ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx ); </TD></TR></TBODY></TABLE><BR>　　该函数如调用成功，则返回一个非0值，表明<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>中已经注册了一个名为EasyWin的窗口类。如果失败，则返回0。<BR><BR><BR>　　<B>创建窗口</B> <BR><BR>　　当窗口类注册完毕之后，并不会有窗口显示出来，因为注册的过程仅仅是为创建窗口所做的准备工作。实际创建一个窗口的是通过调用CreateWindow()函数完成的。窗口类中已经预先定义了窗口的一般属性，而CreateWindow()中的参数可以进一步指定一个窗口的更具体的属性，在EasyWin<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中，是如下调用CreateWindow()函数来创建窗口的： <BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>hwnd = CreateWindow(<BR><BR>"EasyWin", //创建窗口所用的窗口类的名称*<BR><BR>"一个基本的Win32<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>", //窗口标题<BR><BR>WS_OVERLAPPEDWINDOW, //窗口风格，定义为普通型*<BR><BR>100, //窗口位置的x坐标<BR><BR>100, //窗口位置的y坐标<BR><BR>400, //窗口的宽度<BR><BR>300, //窗口的高度<BR><BR>NULL, //父窗口句柄<BR><BR>NULL, //菜单句柄<BR><BR>hInstance, //应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>实例句柄*<BR><BR>NULL ); //一般都为NULL</TD></TR></TBODY></TABLE><BR>　　CreateWindow()函数的参数的含义在上面的注释中已有介绍，注释后打了星号标记的参数应该着重注意，其它的参数都很简单，不多做介绍，可参看<A href="http://www.chinaitpower.com/Dev/Programme/VC/index.html" target=_blank>VC</A>的帮助。<BR><BR>　　第一个参数是创建该窗口所使用的窗口类的名称，注意这个名称应与前面所注册的窗口类的名称一致。<BR><BR>　　第三个参数为创建的窗口的风格，下表列出了常用的窗口风格：<BR><BR>
<TABLE cellSpacing=0 width="100%" border=1>
<TBODY>
<TR>
<TD width="23%">风格</TD>
<TD width="77%">含义 </TD></TR>
<TR>
<TD width="23%">WS_OVERLAPPEDWINDOW</TD>
<TD width="77%">创建一个层叠式窗口，有边框、标题栏、<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>菜单、最大最小化按钮，是以下几种风格的集合：WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, WS_MAXIMIZEBOX </TD></TR>
<TR>
<TD width="23%">WS_POPUPWINDOW </TD>
<TD width="77%">创建一个弹出式窗口，是以下几种风格的集合： WS_BORDER,WS_POPUP,WS_SYSMENU。WS_CAPTION与WS_POPUPWINDOW风格必须一起使用才能使窗口菜单可见 </TD></TR>
<TR>
<TD width="23%">WS_OVERLAPPED</TD>
<TD width="77%">创建一个层叠式窗口，它有标题栏和边框，与WS_TILED风格一样 </TD></TR>
<TR>
<TD width="23%">WS_POPUP</TD>
<TD width="77%">该窗口为弹出式窗口，不能与WS_CHILD同时使用 </TD></TR>
<TR>
<TD width="23%">WS_BORDER</TD>
<TD width="77%">窗口有单线边框 </TD></TR>
<TR>
<TD width="23%">WS_CAPTION</TD>
<TD width="77%">窗口有标题栏 </TD></TR>
<TR>
<TD width="23%">WS_CHILD</TD>
<TD width="77%">该窗口为子窗口，不能与WS_POPUP同时使用 </TD></TR>
<TR>
<TD width="23%">WS_DISABLED </TD>
<TD width="77%">该窗口为无效，即对用户操作不产生任何反应</TD></TR>
<TR>
<TD width="23%">WS_HSCROLL</TD>
<TD width="77%">窗口有水平滚动条 </TD></TR>
<TR>
<TD width="23%">WS_ICONIC</TD>
<TD width="77%">窗口初始化为最小化 </TD></TR>
<TR>
<TD width="23%">WS_MAXIMIZE </TD>
<TD width="77%">窗口初始化为最大化 </TD></TR>
<TR>
<TD width="23%">WS_MAXIMIZEBOX </TD>
<TD width="77%">窗口有最大化按钮 </TD></TR>
<TR>
<TD width="23%">WS_MINIMIZE</TD>
<TD width="77%">与WS_MAXIMIZE一样 </TD></TR>
<TR>
<TD width="23%">WS_MINIMIZEBOX</TD>
<TD width="77%">窗口有最小化按钮 </TD></TR>
<TR>
<TD width="23%">WS_SIZEBOX</TD>
<TD width="77%">边框可进行大小控制的窗口 </TD></TR>
<TR>
<TD width="23%">WS_SYSMENU</TD>
<TD width="77%">创建一个有<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>菜单的窗口，必须与WS_CAPTION风格同时使用 </TD></TR>
<TR>
<TD width="23%">WS_THICKFRAME</TD>
<TD width="77%">创建一个大小可控制的窗口，与WS_SIZEBOX 风格一样.</TD></TR>
<TR>
<TD width="23%">WS_TILED</TD>
<TD width="77%">创建一个层叠式窗口，有标题栏 </TD></TR>
<TR>
<TD width="23%">WS_VISIBLE</TD>
<TD width="77%">窗口为可见 </TD></TR>
<TR>
<TD rowSpan=2>WS_VSCROLL</TD>
<TD rowSpan=2>窗口有垂直滚动条 </TD></TR>
<TR></TR></TBODY></TABLE><BR>　　<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中使用了WS_OVERLAPPEDWINDOW标志，它是创建一个普通窗口常用的标志。而在DirectX编程中，我们常用的是WS_POPUP，用这个标志创建的窗口没有标题栏和<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>菜单，如果设定窗口为最大化，客户区可以占满整个屏幕，以满足DirectX编程的需要。<BR><BR>　　CreateWindow()函数后面的参数中，仍用到了该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的实例句柄hInstance。<BR><BR>　　如果窗口创建成功，返回值是新窗口的句柄，否则返回NULL。<BR><BR><BR>　　<B>显示和更新窗口 </B><BR><BR>　　窗口创建后，并不会在屏幕上显示出来，要真正把窗口显示在屏幕上，还得使用ShowWindow()函数，其原型如下： <BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>BOOL ShowWindow( HWND hWnd, int nCmdShow ); </TD></TR></TBODY></TABLE><BR>　　参数hWnd指定要显示得窗口的句柄，nCmdShow表示窗口的显示方式，这里指定为从WinMain()函数的nCmdShow所传递而来的值。<BR><BR>　　由于ShowWindow()函数的执行优先级不高，所以当<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>正忙着执行其它的任务时，窗口不会立即显示出来，此时，调用UpdateWindow()函数以可以立即显示窗口。其函数原型如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>BOOL UpdateWindow( HWND hWnd ); </TD></TR></TBODY></TABLE><BR>　　<B>消息循环 </B><BR><BR>　　在Win32编程中，消息循环是相当重要的一个概念，看似很难，但是使用起来却是非常简单。在WinMain()函数中，调用InitWindow()函数成功的创建了应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>主窗口之后，就要启动消息循环，其代码如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>while (GetMessage(&amp;msg, NULL, 0, 0))<BR><BR>{<BR><BR>TranslateMessage(&amp;msg);<BR><BR>DispatchMessage(&amp;msg);<BR><BR>}<BR></TD></TR></TBODY></TABLE><BR>　　Windows应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>可以接收以各种形式输入的信息，这包括键盘、鼠标动作 、记时器产生的消息，也可以是其它应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>发来的消息等等。Windows<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>自动监控所有的输入设备，并将其消息放入该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的消息队列中。<BR><BR>　　GetMessage()函数则是用来从应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>的消息队列中按照先进先出的原则将这些消息一个个的取出来，放进一个MSG结构中去。GetMessage()函数原型如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>BOOL GetMessage(<BR><BR>LPMSG lpMsg, //指向一个MSG结构的指针，用来保存消息<BR><BR>HWND hWnd, //指定哪个窗口的消息将被获取<BR><BR>UINT wMsgFilterMin, //指定获取的主消息值的最小值<BR><BR>UINT wMsgFilterMax //指定获取的主消息值的最大值<BR><BR>);<BR></TD></TR></TBODY></TABLE><BR>　　GetMessage()将获取的消息复制到一个MSG结构中。如果队列中没有任何消息，GetMessage()函数将一直空闲直到队列中又有消息时再返回。如果队列中已有消息，它将取出一个后返回。MSG结构包含了一条Windows消息的完整信息，其定义如下：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>typedef struct tagMSG { <BR><BR>HWND hwnd; //接收消息的窗口句柄<BR><BR>UINT message; //主消息值<BR><BR>WPARAM wParam; //副消息值，其具体含义依赖于主消息值<BR><BR>LPARAM lParam; //副消息值，其具体含义依赖于主消息值<BR><BR>DWORD time; //消息被投递的时间<BR><BR>POINT pt; //鼠标的位置<BR><BR>} MSG;</TD></TR></TBODY></TABLE><BR>　　该结构中的主消息表明了消息的类型，例如是键盘消息还是鼠标消息等，副消息的含义则依赖于主消息值，例如：如果主消息是键盘消息，那么副消息中则存储了是键盘的哪个具体键的信息。<BR><BR>　　GetMessage()函数还可以过滤消息，它的第二个参数是用来指定从哪个窗口的消息队列中获取消息，其它窗口的消息将被过滤掉。如果该参数为NULL，则GetMessage()从该应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>线程的所有窗口的消息队列中获取消息。<BR><BR>　　第三个和第四个参数是用来过滤MSG结构中主消息值的，主消息值在wMsgFilterMin和wMsgFilterMax之外的消息将被过滤掉。如果这两个参数为0，则表示接收所有消息。<BR><BR>　　当且仅当GetMessage()函数在获取到WM_QUIT消息后，将返回0值，于是<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>退出消息循环。<BR><BR>　　TranslateMessage()函数的作用是把虚拟键消息转换到<A href="http://www.chinaitpower.com/Dev/Programme/VC/Str/index.html" target=_blank>字符</A>消息，以满足键盘输入的需要。DispatchMessage()函数所完成的工作是把当前的消息发送到对应的窗口过程中去。<BR><BR>　　开启消息循环其实是很简单的一个步骤，几乎所有的<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>都是按照EasyWin的这个方法。你完全不必去深究这些函数的作用，只是简单的照抄就可以了。 <BR>　<BR><BR>　　<B>消息处理函数</B> <BR><BR>　　消息处理函数又叫窗口过程，在这个函数中，不同的消息将用switch语句分配到不同的处理<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中去。Windows的消息处理函数都有一个确定的样式，即这种函数的参数个数和类型以及其返回值的类型都有明确的规定。在<A href="http://www.chinaitpower.com/Dev/Programme/VC/index.html" target=_blank>VC</A>的说明书中，消息处理函数的原型是这样定义的：<BR><BR>
<TABLE class=txcode cellSpacing=0 cellPadding=0 align=center border=0>
<TBODY>
<TR>
<TD>LRESULT CALLBACK WindowProc( <BR><BR>HWND hwnd, //接收消息窗口的句柄<BR><BR>UINT uMsg, //主消息值<BR><BR>WPARAM wParam, //副消息值<BR><BR>LPARAM lParam //副消息值<BR><BR>); </TD></TR></TBODY></TABLE><BR>　　如果你的<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中还有其它的消息处理函数，也都必须按照上面的这个样式来定义，但函数名称可以随便取。EasyWin中的WinProc()函数就是这样一个典型的消息处理函数。<BR><BR>　　消息处理函数的四个参数是由GetMessage()函数从消息队列中获得MSG结构，然后分解后得到的。第二个参数uMsg和MSG结构中的message值是一致的，代表了主消息值。<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中用switch语句来将不同类型的消息分配到不同的处理<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>中去。<BR><BR>　　WinProc()函数明确的处理了4个消息，分别是WM_KEYDOWN（击键消息）、WM_RBUTTONDOWN（鼠标右键按下消息）、WM_PAINT（窗口重画消息）、WM_DESTROY（销毁窗口消息）。<BR><BR>　　值得注意的是，应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>发送到窗口的消息远远不止以上这几条，象WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等这样频频使用的消息就有几十条。为了减轻编程的负担，Windows的API提供了DefWindowProc()函数来处理这些最常用的消息，调用了这个函数后，这些消息将按照<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>默认的方式得到处理。<BR><BR>　　因此，在switch_case语句中，只须明确的处理那些有必要进行特别响应的消息，把其余的消息交给DefWindowProc()函数来处理，是一种明智的选择,也是你必须做的一件事。 <BR>　<BR>　　<B>结束消息循环</B> <BR><BR>　　当用户按Alt+F4或单击窗口右上角的退出按钮，<A href="http://www.chinaitpower.com/System/index.html" target=_blank>系统</A>就向应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>发送一条WM_DESTROY的消息。在处理此消息时，调用了PostQuitMessage()函数，该函数会给窗口的消息队列中发送一条WM_QUIT的消息。在消息循环中，GetMessage()函数一旦检索到这条消息，就会返回FALSE，从而结束消息循环，随后，<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>也结束。 <BR><BR>　　<B>小结 </B><BR><BR>　　本章介绍的是Win32编程的基础知识，在进行DirectX编程之前，掌握它们是十分必要的。<BR><BR>　　通过本文的学习，你应该学到以下知识：<BR><BR>　　　如何创建一个Win32应用<A href="http://www.chinaitpower.com/Dev/index.html" target=_blank>程序</A>工程 <BR><BR>　　　用RegisterClass()函数注册一个窗口类，再立即调用CreateWindow()函数创建一个窗口的实例 <BR><BR>　　　设置窗口的类型以及将一个消息处理函数与窗口联系上 <BR><BR>　　　用一固定的模式开启消息循环 <BR><BR>　　　了解消息处理函数的定义规则，如何自己定义一个窗口消息处理函数 <BR><BR>　　　在消息处理函数中，最后必须调用DefWindowProc()函数以处理那些缺省的消息 <BR><BR>　　　调用PostQuitMessage()函数以结束消息循环 <BR><BR><img src ="http://www.cppblog.com/ivenher/aggbug/1075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-11 13:44 <a href="http://www.cppblog.com/ivenher/articles/1075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC中一些使用的方法</title><link>http://www.cppblog.com/ivenher/articles/1074.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 11 Nov 2005 05:34:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1074.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1074.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1074.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1074.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1074.html</trackback:ping><description><![CDATA[<H2><A id=viewpost1_TitleUrl href="http://gaowg.cnblogs.com/archive/2005/09/07/231649.html"></A>&nbsp;</H2>
<DIV class=postbody>
<P>&nbsp;1．&nbsp; 在CSatic控件上增加图标及位图</P>
<P>CStatic *pStat = NULL;</P>
<P>pStat = (CStatic*)GetDlgItem(控件ID);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pStat-&gt;ModifyStyle(SWP_NOZORDER, SS_ICON);</P>
<P>&nbsp;&nbsp; 可用两种方法增加图标</P>
<P>(1)&nbsp;&nbsp;&nbsp; pStat-&gt;SetIcon(AfxGetApp()-&gt;LoadIcon(图标ID));</P>
<P>(2)&nbsp;&nbsp;&nbsp; pStat-&gt;SetIcon(LoadIcon(::AfxGetInstanceHandle(),”图标名称”)); //图标名字改为“IDI_ICON”的形式，因为这里要求的是字符串形式的名称。</P>
<P>&nbsp;&nbsp; 增加Bmp图片的形式同上，将ModifyStyle中的SS_ICON改为SS_BITMAP。用相应的位图增加函数即可。</P>
<P>2．&nbsp; CClientDC，CWindowDC</P>
<P>这两个类都从CDC类派生，CClientDC类用于获取客户区的DC（不包括标题栏，菜单栏，工具栏），创建了CClientDC类对象后不需用ReleaseDC来释放。如：</P>
<P>CCleintDC dc(this);获取本窗口的dc，CClientDC dc(GetParent())可获取父窗口DC，此时就可在非客户区进行dc操作。</P>
<P>CWindowDC 获取整个窗口的dc，可对整个窗口进行操作，CWindowDC(GetParent())　注意在这获得的父窗口对于对话框情况下将是windows窗口，最后无需ReleaseDC释放</P>
<P>GetDesktopWindow()获取桌面窗口句柄。</P>
<P>::CreateIC("DISPLAY",NULL,NULL,NULL);获取桌面的HDC</P>
<P>3．&nbsp; 获取随机数rand()</P>
<P>要获取一定范围内的随机数可用：</P>
<P>Srand((unsigned) time(NULL));&nbsp;&nbsp; //意思是每次产生的随机数都不相同.</P>
<P>(int)(rand())/(float) RAND_MAX * 10); //返回1－10之间的随机数</P>
<P><BR>&nbsp;4．&nbsp; 获取路径：</P>
<P>char path[MAX_PATH] = "\0";</P>
<P>&nbsp;GetModuleFileName(NULL, path, MAX_PATH);&nbsp; //应用程序路径</P>
<P>&nbsp;GetSystemDirectory();&nbsp; //获取Windows系统目录路径</P>
<P>&nbsp;GetWindowDirectory()&nbsp; //获取Windows目录路径</P>
<P><BR>&nbsp;5．&nbsp; 动态加载ODBC数据源</P>
<P>//mdbName为数据库名称, DSN为数据源名称</P>
<P>&nbsp;void&nbsp; SetODBCSource(char * mdbName ,char * DSNName)&nbsp; </P>
<P>{</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char path[256]="";</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char pathMDB[256]="";</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetAppPath(path);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(pathMDB,path);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(pathMDB, "\\");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(pathMDB, mdbName);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char MdbConfig[256]= "DSN=" ;// pwd</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(MdbConfig , DSNName);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char * pMconfig = MdbConfig + strlen(MdbConfig) + 1 ;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(pMconfig,"DBQ=");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pMconfig += 4;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(pMconfig,pathMDB);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pMconfig += strlen(pathMDB) + 1 ;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(pMconfig,"DEFAULTDIR=");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(pMconfig,path);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(pMconfig,"\0");</P>
<P>if(!SQLConfigDataSource(NULL,ODBC_ADD_SYS_DSN,"Microsoft&nbsp; Access </P>
<P>Driver (*.mdb)\0",MdbConfig))&nbsp; //注意Driver后的空格</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRACE("加载数据库失败,请检查数据库是否存在\n");</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P><BR>6．&nbsp; 线程退出</P>
<P>线程退出请使用return 或 ExitThread()来正常退出线程，尽是避免使用TerminateThread来终止线程，因为终止后线程资源将不会被释放。</P>
<P>一般情况下在CreateThread创建了线程后即使用CloseHandle()来关闭线程句柄，以防止TerminateThread得到句柄后，进行线程的强制终止。</P>
<P><BR>&nbsp;7．&nbsp; 自定义宏检查错误BOOL错误。</P>
<P>#define ASSERT_ERROR(Code)\</P>
<P>{\</P>
<P>&nbsp;&nbsp; If (Code)\</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(“提示1 “);\</P>
<P>&nbsp;&nbsp; Else \</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(“错误1”);\</P>
<P>}</P>
<P>定义以后可在需要使用的地方使用，如：BOOL bStat = TRUE;</P>
<P>ASSERT_ERROR(bStat); //此时将执行“提示1”，bStat = FALSE时执行“错误1”</P>
<P><BR>&nbsp;8．&nbsp; 将程序加入注册表启动项：</P>
<P>LPCTSTR lpcAppPath = “程序路径”;</P>
<P>CString str = “SOFTWARE\\Microsoft\\Windows\\CurrentverSion\\Run”;</P>
<P>HKEY hResult;</P>
<P>RegOpenKey(HKEY_LOCAL_MACHINE, (LPCSTR)str.GetBuffer(0), &amp;hResult);</P>
<P>RegSetValueEx(hResult, “程序名称”, 0, REG_SZ, (const unsigned char*)lpcAppPath,</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sizeof(char) * strlen(lpcAppPath));</P>
<P>RegCloseKey(hResult);</P>
<P><BR>&nbsp;9．&nbsp; 程序调试</P>
<P>在调试环境下的Vlaue窗口中输入” @err,hr”　可返回当前发生的错误原因</P>
<P><BR>&nbsp;10．&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 获取工具条指针，工具条有一特殊标识(AFX_IDW_TOOLBAR)</P>
<P>CToolBar *pTool = (CToolBar*)AfxGetMainWnd()-&gt;GetDescendantWindow(特殊标识)</P>
<P>;</P>
<P>获取状态条指针。</P>
<P>(CStatusBar*)AfxGetMainWnd()-&gt;GetDescendantWindow(AFX_IDW_STATUS_BAR);</P>
<P><BR>&nbsp;获取主窗口指针：</P>
<P>CMainFrame *pFrame = (CMainFrame*)(AfxGetApp()-&gt;m_pMainWnd);</P>
<P><BR><BR>获取视类指针：</P>
<P>CMyView *pView= CMyView*)((CMainFrame*)AfxGetApp()-&gt;m_pMainWnd)-&gt;GetActiveView();</P>
<P>&nbsp;</P>
<P>或</P>
<P>&nbsp;</P>
<P>CMyView *pView=(CMyView*)GetActiveView();</P>
<P><BR>11．显示或隐藏任务栏:</P>
<P>&nbsp;::ShowWindow(::FindWindow(“Shell_TrayWnd”, NULL, SW_SHOW)，隐藏用SW_HIDE</P>
<P>&nbsp;12．使用基于对话框的程序在任务栏隐藏。</P>
<P>&nbsp;This-&gt;ModifyStyleEx(WS_EX_APPWINDOW, 0);</P>
<P>&nbsp;13．只允许程序运行一个实例：</P>
<P>&nbsp;HANDLE h_Muex = CreateMutex(NULL, TRUE, m_pszAppName);</P>
<P>&nbsp;If (GetLastError() == ERROR_ALREADY_EXISTS)</P>
<P>&nbsp;&nbsp;&nbsp; Return False;<BR><BR></P></DIV><img src ="http://www.cppblog.com/ivenher/aggbug/1074.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-11 13:34 <a href="http://www.cppblog.com/ivenher/articles/1074.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC变量类型全集 </title><link>http://www.cppblog.com/ivenher/articles/1071.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 11 Nov 2005 05:20:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1071.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1071.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1071.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1071.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1071.html</trackback:ping><description><![CDATA[<FONT color=#000000 size=4>MFC变量类型全集</FONT> 
<P><FONT size=5>
<P><FONT face=Verdana size=2></FONT></P>
<H1><A name=_mfc_data_types></A>Data Types</H1>
<P>This topic lists the data types most commonly used in the Microsoft Foundation Class Library. Most of the data types are exactly the same as those in the Windows Software Development Kit (SDK), while others are unique to MFC.</P>
<P>Commonly used Windows SDK and MFC data types are as follows: 
<UL type=disc>
<LI><B>BOOL</B>&nbsp;&nbsp;&nbsp;A Boolean value.<BR><BR>
<LI><B>BSTR</B>&nbsp;&nbsp;&nbsp;A 32-bit character pointer.<BR><BR>
<LI><B>BYTE</B>&nbsp;&nbsp;&nbsp;An 8-bit integer that is not signed.<BR><BR>
<LI><B>COLORREF</B>&nbsp;&nbsp;&nbsp;A 32-bit value used as a color value.<BR><BR>
<LI><B>DWORD</B>&nbsp;&nbsp;&nbsp;A 32-bit unsigned integer or the address of a segment and its associated offset.<BR><BR>
<LI><B>LONG</B>&nbsp;&nbsp;&nbsp;A 32-bit signed integer.<BR><BR>
<LI><B>LPARAM</B>&nbsp;&nbsp;&nbsp;A 32-bit value passed as a parameter to a window procedure or callback function.<BR><BR>
<LI><B>LPCSTR</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to a constant character string.<BR>typedef CONST CHAR *LPCSTR, *PCSTR;<BR>
<LI><B>LPSTR</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to a character string.<BR><BR>
<LI><B>LPCTSTR</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to a constant character string that is portable for Unicode and DBCS.<BR><BR>
<LI><B>LPTSTR</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to a character string that is portable for Unicode and DBCS.<BR><BR>
<LI><B>LPVOID</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to an unspecified type.<BR><BR>
<LI><B>LRESULT</B>&nbsp;&nbsp;&nbsp;A 32-bit value returned from a window procedure or callback function.<BR><BR>
<LI><B>UINT</B>&nbsp;&nbsp;&nbsp;A 16-bit unsigned integer on Windows versions 3.0 and 3.1; a 32-bit unsigned integer on Win32.<BR><BR>
<LI><B>WNDPROC</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to a window procedure.<BR><BR>
<LI><B>WORD</B>&nbsp;&nbsp;&nbsp;A 16-bit unsigned integer.<BR><BR>
<LI><B>WPARAM</B>&nbsp;&nbsp;&nbsp;A value passed as a parameter to a window procedure or callback function: 16 bits on Windows versions 3.0 and 3.1; 32 bits on Win32. </LI></UL>
<P>Data types unique to the Microsoft Foundation Class Library include the following: 
<UL type=disc>
<LI><B>POSITION</B>&nbsp;&nbsp;&nbsp;A value used to denote the position of an element in a collection; used by MFC collection classes.<BR><BR>
<LI><B>LPCRECT</B>&nbsp;&nbsp;&nbsp;A 32-bit pointer to a constant (nonmodifiable) <B>RECT</B> structure. </LI></UL></FONT><img src ="http://www.cppblog.com/ivenher/aggbug/1071.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-11 13:20 <a href="http://www.cppblog.com/ivenher/articles/1071.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>