fbpx
维基百科

MFC (微軟)

微软基础类库(英語:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows API,并且包含一个(也是微软产品的唯一一个)应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。

特性 编辑

Visual C++包含MFC应用程序向导,可用于兼容MFC的应用程序[1]。在ATL程序中也可以手动添加MFC支持[2]。在向导中有各种选项以定制生成的程序的功能,例如界面风格、语种、数据库开发支持、打印支持、自动化支持、ActiveX支持、网络支持、基于HTML的帮助文档支持等等。

COM开发方面,相对于ATL来说,MFC的组件比较大,代码不够短小精悍,但是支持的功能也比较多,例如有对ActiveX Document的封装类[3]

在界面开发方面,MFC提供对消息循环的封装,使用消息映射来避免虚函数的开销。MFC也提供常用Windows通用控件的封装类。

MFC扩展DLL的接口使得MFC程序可以直接调用MFC扩展DLL中的MFC类。MFC也支持在标准DLL中被使用。

发展 编辑

MFC是在1992年随微软的Microsoft C/C++ 7.0编译器发布的,用于面向16位元Windows的软件开发。起初,MFC是作为一个应用程序框架开发的,所以定名为Application Framework eXtensions(AFX)。[4]

随着.NET框架的发布,曾经一度被微软重点推荐的MFC被Visual Basic .NETC#Windows Forms抢走了不少市场份额,但是MFC继续在非托管软件开发中占据重要地位。在托管开发方面,MFC中也包括对Windows Forms和托管/非托管互操作的封装。微软在Windows VistaWindows 7发布之后在MFC中增加了对新的Windows API支持[5][6]

MFC的优点 编辑

MFC的主要优点是可以用面向对象的方法来调用Windows API,以及能够更加便捷地开发应用程序。MFC将很多应用程序开发中常用的功能自动化,并且提供了文档框架视图结构和活动文档这样的便于自定义的应用程序框架。同时,在Visual C++内部也内建了很多对MFC的例如类向导这样的支持以减少软件开发的时间,使用类向导可以快速生成Hello World程序。

MFC的缺点 编辑

虽然MFC的源代码对用户是完全开放的,但是MFC的一些封装过程过于复杂,以致于新用户很难迅速掌握MFC的应用程序框架,以及在调试中定位问题的位置。同时,很多MFC对象不是线程安全的,致使在跨线程访问MFC对象时需要编写额外的代码。另外,MFC的很多类依赖于应用程序向导生成的代码,使得在使用Visual C++中其他类型的应用程序向导生成的工程中添加MFC支持的难度大大增加。

第三方支持 编辑

很多商用类库在MFC的基础上进一步实现了皮肤、渐变风格、多顶层窗口程序、属性列表等较受欢迎的功能;同时,在C++在线社区中,很大一部分开放的源代码也是基于MFC的。


版本 编辑

產品 程式庫 版本 發佈日期
名稱 版本
Microsoft C/C++ 7.0 mafxcw.lib MFC 1.0 1992
Microsoft Visual C++ 1.0 Visual C++ 1.0 mfc200.dll MFC 2.0
Visual C++ 1.5 mfc250.dll MFC 2.5
Visual C++ 1.51 mfc250.dll MFC 2.51
Visual C++ 1.52c mfc250.dll MFC 2.5 ( Windows 3.x 的最後發展平台 )
Microsoft Visual C++ 2.0 Visual C++ 2.0 mfc30.dll MFC 3.0
Visual C++ 2.1 mfc30.dll MFC 3.1
Visual C++ 2.2 mfc30.dll MFC 3.2
Microsoft Visual C++ 4.0 Visual C++ 4.0 mfc40.dll MFC 4.0 (mfc40.dll 包含於 Windows 95) 1995年8月
Visual C++ 4.1 mfc40.dll MFC 4.1
Visual C++ 4.2 mfc42.dll MFC 4.2 (mfc42.dll 包含於 Windows 98 初版) 1998年3月
內含於 Visual C++ 3.0 mfc42.dll MFC 4.2
Microsoft Visual C++ 5.0 Visual C++ 5.0 mfc42.dll MFC 4.21, 是 MFC 4.2 的主要更新
Microsoft Visual C++ 6.0 Visual C++ 6.0 mfc42.dll MFC 6.0 1998年
內含於 Visual C++ 4.0 mfcce400.dll MFC 6.0
Microsoft Visual C++ .NET 2002 Visual C++ .NET 2002 (Visual C++ 7.0) mfc70.dll MFC 7.0 2002年2月13日
Microsoft Visual C++ .NET 2003 Visual C++ .NET 2003 (Visual C++ 7.1) mfc71.dll MFC 7.1 2003年4月24日
Visual C++ .NET 2003 + MS11-025 (KB2465373)[7] MFC 7.10.6119.0 2011年4月12日
Microsoft Visual C++ 2005 Visual C++ 2005 (Visual C++ 8.0) mfc80.dll 8.0.50727.42 2006年4月10日
Visual C++ 2005 SP1 8.0.50727.762 2007年8月27日
Visual C++ 2005 SP1 + MS09-035 (KB973544)[8][9] 8.0.50727.4053 2009年7月28日
Visual C++ 2005 SP1 + MS11-025 (KB2467175)[7] 8.0.50727.5592 2011年4月12日
Visual C++ 2005 SP1 + MS11-025 (KB2538242)[7][10] 8.0.50727.6195 (包含於 redist 8.0.61000/8.0.61001[11]) 2011年6月14日
Microsoft Visual C++ 2008 Visual C++ 2008 (Visual C++ 9.0) mfc90.dll 9.0.21022.8 2007年11月19日
Visual C++ 2008 + MS09-035 (KB973551)[8][9] 9.0.21022.218 2009年7月28日
Visual C++ 2008 含Feature Pack 9.0.30411 2008年4月22日
Visual C++ 2008 SP1 9.0.30729.1 2008年8月11日
Visual C++ 2008 SP1 + MS09-035 (KB973552)[8][9] 9.0.30729.4148 2009年7月28日
Visual C++ 2008 SP1 + MS11-025 (KB2467174)[7] 9.0.30729.5570 2011年4月12日
Visual C++ 2008 SP1 + MS11-025 (KB2538243)[7] 9.0.30729.6161 (安裝程式版本 9.0.30729.5677) 2011年6月14日
Microsoft Visual C++ 2010 Visual C++ 2010 (Visual C++ 10.0) mfc100.dll 10.0.30319.1 2010年4月12日[12]
Visual C++ 2010 + MS11-025 (KB2467173)[7] 10.0.30319.415 2011年4月12日
Visual C++ 2010 SP1 10.0.40219.1 2011年3月10日
Visual C++ 2010 SP1 + MS11-025 (KB2565063)[7] 10.0.40219.325 2011年8月9日
Microsoft Visual C++ 2012 Visual C++ 2012 (Visual C++ 11.0) mfc110.dll 11.0.50727.1 2012年9月12日
Visual C++ 2012 Update 1 11.0.51106.1 2012年11月26日
Visual C++ 2012 Update 3 11.0.60610.1 2013年6月26日
Visual C++ 2012 Update 4 11.0.61030.0 2013年11月13日
Microsoft Visual C++ 2013 Visual C++ 2013 (Visual C++ 12.0) mfc120.dll 12.0.21005.1 2013年10月17日
Visual C++ 2013 Update 2 12.0.30501.0 2014年5月12日
Visual C++ 2013 Update 5 + KB3138367 12.0.40649.5 2016年2月?
Visual C++ 2013 Update 5 + KB3179560 12.0.40660.0 2016年7月8日[13]
Visual C++ 2013 Update 5 + KB4032938 12.0.40664.0 2017年7月18日[14]
Microsoft Visual C++ 2015 Visual C++ 2015 (Visual C++ 14.0) mfc140.dll 14.0.23026.0 2015年7月20日
Visual C++ 2015 Update 1 14.0.23506.0 2015年11月30日[15]
Visual C++ 2015 Update 2 14.0.23918.0 2016年3月30日[16]
Visual C++ 2015 Update 3 14.0.24210.0 2016年6月27日[17]
Visual C++ 2015 Update 3 14.0.24212.0 2016年8月18日
Visual C++ 2015 Update 3 + KB3165756 14.0.24215.1 2016年9月15日[18]
Microsoft Visual C++ 2017 Visual C++ 15.0 mfc140.dll 14.10.25008.0 2017年3月7日
Visual C++ 15.1? 14.10.25017.0 2017年4月5日?
Visual C++ 15.2 14.11.25325.0 2017年5月10日
Visual C++ 15.4 14.12.25810.0 2017年10月9日
Visual C++ 15.6 14.13.26020.0 2018年3月5日
Visual C++ 15.7 14.14.26405.0 2018年5月7日
Visual C++ 15.7.3? 14.14.26429.4 2018年5月31日
Visual C++ 15.8 14.15.26706.0 2018年8月14日
Visual C++ 15.9 14.16.27012.6 2018年11月13日
Visual C++ 15.9.5 14.16.27024.1 2019年1月8日
Visual C++ 15.9.6 14.16.27026.1 2019年1月24日
Visual C++ 15.9.9 14.16.27027.1 2019年3月12日
Visual C++ 15.9.15 14.16.27033.0 2019年8月13日
Microsoft Visual C++ 2019 Visual C++ 16.0.0 mfc140.dll 14.20.27508.1 2019年4月2日?
Visual C++ 16.1.0 14.21.27702.2 2019年5月21日
Visual C++ 16.2.0 14.22.27821.0 2019年7月24日
Visual C++ 16.3.0 14.23.27820.0 2019年9月23日
Visual C++ 16.4.0 14.24.28127.4 2019年12月3日
Visual C++ 16.5.0 14.25.28508.3 2020年3月16日
Visual C++ 16.6.0 14.26.28720.3 2020年5月19日
Visual C++ 16.6.3 14.26.28808.1 2020年7月30日
Visual C++ 16.7.0 14.27.29016.0 2020年8月5日
Visual C++ 16.7.5 14.27.29112.0 2020年9月29日
Visual C++ 16.8.0 14.28.29325.2 2020年11月10日
Visual C++ 16.8.2 14.28.29334.0 2020年11月19日
Visual C++ 16.9.0 14.28.29910.0 2021年3月2日
Visual C++ 16.9.2 14.28.29913.0 2021年3月16日
Visual C++ 16.9.4 14.28.29914.0 2021年4月13日
Visual C++ 16.10.0 14.29.30037.0 2021年5月25日
Visual C++ 16.10.2 14.29.30038.0 2021年6月15日
Visual C++ 16.10.4 14.29.30040.0 2021年7月20日
Visual C++ 16.11.0 14.29.30133.0 2021年8月10日
Visual C++ 16.11.4 14.29.30135.0 2021年10月5日
Microsoft Visual C++ 2022 Visual C++ 17.0.0RC mfc140.dll 14.30.30704.0 2021年10月13日


  • 1 Visual Studio速成版(Express)不包含MFC程式库。
  • 2 Feature Pack只用于英文版本的Visual Studio 2008。非英文版本的支援於将包含于Visual Studio 2008 Service Pack 1。

MFC的结构 编辑

作为一个应用程序的开发框架,必须满足各方面的功能需求。

应用程序启动 编辑

基于MFC开发的应用程序在启动时,Windows操作系统:

  1. 首先调用WinMain函数(位于appmodul.cpp中,封装到mfc80.dll(VS2005版)),WinMain函数内调用了AfxWinMain函数。
  2. AfxWinMain函数(位于WinMain.cpp中)调用了
    1. 该应用程序自定义的App类(这个类派生于CWinApp的,CWinApp又是派生于CWinThread,因此代表了应用程序的主线程)的InitInstance函数,该函数注册并创建窗口(通过AppUI2.cpp中的ProcessShellCommmand函数),然后ShowWindow、UpdateWindow;
    2. CWinThread的InitInstance函数;
    3. CWinThread的Run函数(位于thrdcore.cpp中)。该函数内部是Windows的消息循环。 当应用程序收到WM_QUIT消息后,CWinThread::Run函数返回,紧接着CWinThread::ExitInstance被调用,该函数可被覆盖。程序至此退出运行。 消息循环是一个for(;;)的死循环,该死循环内部包含了一个do...while的循环结构。while循环条件是调用PeekMessage函数的返回值,如果当前UI线程消息队列为空就返回到外层的死循环;while循环体内做两件事:
      1. PumpMessage()。实际调用AfxInternalPumpMessage函数实现其功能:GetMessage()、AfxPreTranslateMessage()、TranslateMessage()、DispatchMessage().即:从UI线程消息队列移除一条消息、遍历该消息的CWnd类直到该窗口的各级别父窗口的CWnd类以提供预处理该消息的机会、如果该消息是按键消息则翻译为WM_CHAR消息、把该消息给相应的窗口函数。
      2. IsIdleMessage():实际调用了AfxInternalIsIdleMessage函数,对于WM_PAINT、WM_SYSTIMER、以及光标位置没有变化的WM_MOUSEMOVE或WM_NCMOUSEMOVE,为Idle Message。
    4. 各个窗口函数(WndProc)内部首先获取对应当前窗口句柄的CWnd类的指针,然后调用AfxCallWndProc函数。

应用程序结束 编辑

  • 如果是点击了IDOK按钮,默认是调用OnOK(),然后是OnDestory(),最后是PostNcDestroy()
  • 如果点击IDCANCEL按钮,默认调用OnCancel(),然后是OnDestory(),最后是PostNcDestroy()
  • 如果点击右上角的关闭按钮:先OnClose(),然后是OnCancel(),再然后是OnDestory() ,最后是PostNcDestroy()

消息循环与消息映射 编辑

 
MFC Class hierarchy for Windows message process flow

消息分类 编辑

分类 消息 映射宏 消息处理函数原型 注释
系统消息 标准Windows消息 MFC使用专用的相关的宏。如ON_WM_CREATE() MFC使用专用的消息处理成员函数 一般地由窗口对象来处理这类消息
命令消息 WM_COMMAND ON_COMMAND(id, memberFxn) void OnXXX () 通过标识符ID来区分来自哪个菜单项、工具栏按钮或者加速键等
ON_COMMAND_RANGE(id, idLast, memberFxn) void OnXXX (UINT id) 批量处理一定范围内的标示符ID
ON_UPDATE_COMMAND_UI(id, idLast, memberFxn) void OxXXX(CCmdUI* pCmdUI) 程序空闲时发的界面更新消息的宏
ON_UPDATE_COMMAND_UI_RANGE(id, idLast, memberFxn) void OxXXX(CCmdUI* pCmdUI)
ON_CONTROL(id, idLast, memberFxn) void OnXXX () 父窗口响应控件发送的消息
ON_CONTROL_RANGE(id, idLast, memberFxn) void OnXXX (UINT id)
ON_CONTROL_REFLECT(id, idLast, memberFxn) void OnXXX () 子控件响应父窗口反射回来的通知消息
通知消息WM_NOTIFY ON_NOTIFY(wNotifyCode,id,memberFxn) afx_msg void memberFxn(NMHDR * pNotifyStruct, LRESULT* result) wParam为控件ID,lParam指向NMHDR结构体,结构体的code域值为控件通知码用来表示控件上的动作,如NM_CLICK.一般地由父窗口对象来处理这类消息。
ON_NOTIFY_RANGE( wNotifyCode, id, idLast, memberFxn ) 可手工添加(class wizard不支持),处理控件id连续的一批控件的同一通知码消息。
ON_NOTIFY_EX 允许通知消息在多处被处理
ON_NOTIFY_EX_RANGE
ON_NOTIFY_REFLECT afx_msg void memberFxn(NMHDR * pNotifyStruct, LRESULT* result) 复杂子控件响应父窗口反射回来的通知消息
自定义消息 窗口类内部自定义消息WM_USER到WM_APP-1 ON_MESSAGE(消息名,memberFxn) afx_msg LRESULT OnMyMessageXXX(WPARAM wParam, LPARAM lParam) 示例
程序内部自定义消息WM_APP到0xBFFF ON_THREAD_MESSAGE(WM_THREADMSG,OnThreadMessage) afx_msg void OnThreadMessage(WPARAM wParam,LPARAM lParam); 示例
ON_REGISTERED_THREAD_MESSAGE afx_msg void OnMyRegisterdThreadMsg(WPARAM, LPARAM); RegisterWindowMessage()使用一个字符串来登记一个自定义的消息ID
应用程序之间自定义消息0xC000到0xFFFF ON_REGISTERED_MESSAGE LRESULT OnMyMessageXXX(WPARAM wParam, LPARAM lParam) RegisterWindowMessage()使用一个字符串来登记一个自定义的消息ID,便于跨进程应用

控件的通知消息与反射消息 编辑

窗体上的控件,应当向父窗体通报控件发生的各种事件,如被点击、绘制、内容改变等等,称为通知消息(notification message )。在 Windows 3.x的16位程序设计时代,控件向父窗体发送WM_COMMAND消息,由父窗体的代码负责实现这些事件。其中wParam的低16位是 control ID,高16位是notification code (例如BN_CLICKED);lParam是控件句柄。因此,再无可能传递其它信息给父窗体。为此,为传递具有特别内容的控件事件,Windows 3.x定义了一批特殊的通知消息(notification messages):

  • WM_PARENTNOTIFY:子窗口的某些重大事件发生时通知父窗口,包括创建、销毁、鼠标各键按下等事件
  • 子窗口的滚动情况的通知消息
    • WM_VSCROLL
    • WM_HSCROLL
  • 子窗口的绘制通知消息
    • WM_DRAWITEM,
    • WM_MEASUREITEM,
    • WM_COMPAREITEM,
    • WM_DELETEITEM,
    • WM_CHARTOITEM,
    • WM_VKEYTOITEM
    • WM_CTLCOLOR:设置按钮、编辑框、ListBox、Static、滚动条控件与MessageBox、DialogBox的前景色、背景色、背景模式、字体,并返回一把Brush,用于控件背景绘制。

早于4.0版本的MFC,在控件类提供了虚函数处理这些通知消息,这一办法已经被下述的“消息反射”取代(但仍然向后兼容继续支持)。

随着Windows 95开始了32位程序时代,伴之而来的是Win32 API 与 MFC 4.0。 Win32增加了很多复杂的控件,需要使用更多的通知消息传递很多复杂的数据给父窗体。Win32 API仅仅增加了一个消息WM_NOTIFY,就实现了这些功能。lParam参数开头是NMHDR数据结构,其后是与该通知类型相关的特定数据结构。

typedef struct tagNMHDR {  HWND hwndFrom;  UINT idFrom;  UINT code; } NMHDR; 

CWnd::OnNotify函数处理通知消息。它的默认实现是检查消息映射表(message map)查找通知的处理器函数并调用。一般说来,不必覆盖OnNotify;而应该写一个处理器函数并增加为该窗口类的消息映射表条目。

 ON_NOTIFY(wNotifyCode, id, memberFxn) 

成员函数应该写为:

 afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result); 

MFC 4.0提供了一种特性“消息反射”(message reflection),[19]允许控件通知消息既可以在父窗口中,也可以在控件中被处理。可以对控件创建一个派生的控件类,实现对从父窗口反射回来的指定类型消息的处理。消息反射是MFC而不是Win32的特性,因此父窗口的类必须是从CWnd派生,从而父窗口在CWnd::OnNotify函数中处理控件的WM_NOTIFY时,首先调用CWnd::ReflectLastMsg把消息反射回控件的CWnd::SendChildNotifyLastMsg函数去处理;ReflectLastMsg返回值就是在控件的消息映射中使用ON_NOTIFY_REFLECT_EX()声明的反射消息处理函数的返回值,可以通知父窗口该消息是否已经被控件处理。控件的CWnd::SendChildNotifyLastMsg函数,首先获得线程的最后一条message,然后调用发送窗口的虚函数OnChildNotify函数。在子窗口处理反射回来的控件消息,第一种方法是重载控件窗口的OnChildNotify虚函数;第二种办法是由CWnd::OnChildNotify默认处理去调用CWnd::ReflectChildNotify函数,进入控件子窗口的MFC消息映射的标准处理(子窗口处理的消息被译成WM_REFLECT_BASE+WM_NOTIFY消息)。对于WM_NOTIFY,仅当在控件的消息映射(message map)中,控件没有通过ON_NOTIFY_REFLECT()声明的反射消息处理函数,父窗口的相应的通知消息处理函数才会被调用(在父窗口消息映射中使用宏ON_NOTIFY声明)。控件中通过ON_NOTIFY_REFLECT_EX()声明的反射消息处理函数可以返回真或假,以决定父窗口是否继续处理该通知消息。WM_NOTIFY以外的其它通知消息,父窗口在第一时间有机会处理它,控件对它的处理排在第二位。反射消息处理函数通常使用特定的名字,对应的消息反射宏的名字是在消息名字加上前缀ON_,后缀_REFLECT。如WM_CTLCOLOR对应ON_WM_CTLCOLOR_REFLECT。但以下三种情况,反射消息处理函数可以随意自行起名,对应的消息反射宏的名字分别为:

  • WM_COMMAND使用ON_CONTROL_REFLECT
  • WM_NOTIFY使用ON_NOTIFY_REFLECT
  • ON_UPDATE_COMMAND_UI使用ON_UPDATE_COMMAND_UI_REFLECT

消息传递处理机制 编辑

MFC类体系中,Windows消息传递处理机制是基于CCmdTarget类及其派生类的静态成员函数GetThisMessageMap()内部定义的静态数据成员:

  • 成员类型为AFX_MSGMAP_ENTRY的数组_messageEntries。在类的实现文件中,在BEGIN_MESSAGE_MAP与END_MESSAGE_MAP之间的内容来初始化消息映射入口项数组。
  • 数据类型为AFX_MSGMAP的变量messageMap。该结构包含两项,分别是直接基类GetThisMessageMap函数指针与本类的_messageEntries数组首元素地址。

头文件的类定义中使用宏DECLARE_MESSAGE_MAP()来声明静态成员函数GetThisMessageMap与虚函数GetMessageMap

用户所写的类的Windows消息处理函数(例如OnCommand)必须转换为CCmdTarget::*的成员函数指针类型AFX_PMSG,保存在该类的_messageEntries数组中。

struct AFX_MSGMAP_ENTRY {  UINT nMessage; // windows消息代号  UINT nCode; // WM_NOTIFY的控制代码  UINT nID; // WM_COMMAND下面的ID号,如果为其他的消息,则这个数字为0  UINT nLastID; //和前面的ID一起组成一个范围,用于发送一次消息,处理执行多次  UINT nSig; // 标志消息处理函数的类型  AFX_PMSG pfn; // 函数调用指针 }; typedef void (CCmdTarget::*AFX_PMSG)(void); 

调用用户类中该消息处理函数时,根据该函数保存在_messageEntries中的signature(一个无符号整型表示的函数的形参类型列表与返回值类型),把类型为void (CCmdTarget::*AFX_PMSG)(void)的成员函数指针强制转为其它类型的CCmdTarget成员函数指针(例如void (AFX_MSG_CALL CWnd::*pfn_v_i_i)(int, int),目前在union MessageMapFunctions中列出了近百种CCmdTarget成员函数指针),然后调用转换后的成员函数指针。这是基于Visual C++编译器把单继承的成员函数指针编译为只保存了函数的内存起始地址,因此可以在同一个单继承类中把一种类型的成员函数指针强制转换为另一种成员函数指针,或者把单继承派生类的成员函数指针强制转换为基类成员函数指针。这是打破了C++标准的违例办法。例如,对于CWnd::OnCommand函数,转换过程是:

BOOL (CWnd::*)(WPARAM, LPARAM lParam) => void (CWnd::*)() => void (CCmdTarget::*)() 

CString 编辑

CString是MFC中最常见的类之一,用于封装字符串数据结构。它只有一个数据成员m_pszData,其值为字符串的首地址,其数据类型为wchar_t*或char*。在CString的m_pszData的前面实际还分配了CSringData数据块,包含了管理数据:

IAtlStringMgr* pStringMgr;  int nDataLength;  int nAllocLength;  int nRefs; 

自底向上,CAtlStringMgr提供内存管理,CStringData提供共享管理,CString提供字符串操作。

CAtlStringMgr的一个成员是IAtlMemMgr接口,这是策略模式,可以引用某个内存管理类。CAtlStringMgr的另一个成员是CNilStringData。

因此,每次为CString动态分配地址空间,实际分配长度为:(nChars+1)*nCharSize+sizeof(CStringData)。通过 Attach 操作,将这个 CStringData* 与 CSimpleStringT::m_pszData 执行了关联。当执行CString的默认构造函数生成一个空串时,实际上都是构造一个CnilStringData对象。CNilStringData 派生自 CStringData,额外拥有一个 achNil 的数组成员,这个数组初始化为空字符串。通过这个 achNil,保证了一个经过调用默认构造函数初始化的 CString,其指向的真正的字符串是一个空串。

部分编译器对std::string放弃了写时复制(Copy On Write)机制。但是,CString一直采取这一机制。CSimpleStringT::Fork 函数就提供了这样一个操作,具体分为下面几步:

  1. 根据传入的一个长度分配一段新的空间;—— Allocate(nLength, ...)
  2. 把旧数据拷贝到新的空间里面;—— CopyChars(...)
  3. 旧数据块的引用技术减1; —— pOldData->Release()
  4. 把 m_pszData 和新的数据块关联起来。—— Attach(pNewData)

GetString方法返回的是只读的字符串地址;而GetBuffer方法返回的是可写的字符串地址(如果数据区是共享的,则写时复制),如果修改了字符串内容,这时需要调用ReleaseBuffer方法把新的字符串长度修改到元数据中(并在尾部增加2个0字节)。[20]

CString对象用作可变参数函数(如printf)的实参时,由于无法通过形参类型确定调用哪个CString的类型转换操作符函数,因此有必要显式指明要转换的类型。如果需要在函数的参数传递CString,由于CString使用了引用计数,因此函数参数传递一个CString对象是可行的;不需要修改其内容时,推荐使用const CString&。

支持MFC的DLL开发 编辑

使用Visual C++可以开发3种DLL:

  • 不使用MFC的DLL;
  • 使用MFC的规则的DLL:输出的函数不涉及MFC,因此可以被支持/不支持MFC的应用程序调用该DLL
    • 动态链接到MFC(Regular DLLs dynamically linked to MFC)。
    • 静态链接到MFC(Regular DLLs statically linked to MFC)
  • 使用MFC的扩展DLL(Extension DLLs),只能动态链接到MFC:输出的函数涉及MFC,也可以输出基于MFC的派生类。

由于DLL与调用它的应用程序都可以有自己的MFC全局数据与句柄映射(handle mapping),如果句柄值相同,则默认使用应用程序的映射到的资源。为了不互相干扰,允许DLL内部使用自己的资源,必须在DLL函数的入口处把资源模块句柄从默认的应用程序切换为该DLL。办法是:

  1. 在该DLL的每个输出的函数的最开始之处调用AFX_MANAGE_STATE(AfxGetStaticModuleState( ))[21]。函数AfxGetStaticModuleState的功能是在运行栈上创建一个AFX_MODULE_STATE类的实例,对其进行设置,函数返回值为AFX_MODULE_STATE的指针。AFX_MODULE_STATE类利用其构造函数和析构函数进行模块状态现场存储及恢复。
  2. 使用AfxGetResourceHandle();获取当前资源模块句柄。使用AfxSetResourceHandle(HINSTANCE xxx); 设置程序要使用的资源模块句柄。

常用头文件与库文件 编辑

  • STDAFX.H 载入其他MFC头文件。
  • AFXWIN.H 它和它载入的文件声明了所有的MFC类。其内包含AFX.H,后者包含了AFXVER_.H,后者又载入了AFXV_W32.H,后者又载入WINDOWS.H。
  • AFXEXT.H 使用工具栏、状态栏的程序必须载入这个文件
  • AFXDLGS.H 通用对话框(Common dialog)的MFC程序需要载入此文件。它内部包含COMMDLG.H
  • FXCMN.H 通用控件(common control)的MFC程序需要载入此文件。
  • AFXCOLL.H 使用MFC提供的容器都需要载入此文件。
  • AFXDLLX.H 凡使用MFC extension DLLs需要载入此文件。
  • AFXRES.H MFC程序的RC文件必须载入此文件。此文件中对于标准资源的ID都有默认值。它们定义于此文件中。

参考和引用 编辑

  1. ^ MFC应用程序向导. [2011-05-18]. (原始内容于2016-04-02). 
  2. ^ HOWTO:给ATL项目添加MFC支持. [2010-03-06]. (原始内容于2015-03-11). 
  3. ^ Recommendations for Choosing Between ATL and MFC (页面存档备份,存于互联网档案馆(英文)
  4. ^ Upgrading Relational Databases with Objects, Robert Vermeulen著, 126页
  5. ^ MFC Updates for Vista Common Controls. [2010-03-06]. (原始内容于2010-03-27). 
  6. ^ Making your application sparkle with Windows 7. [2010-03-06]. (原始内容于2010-03-28). 
  7. ^ 7.0 7.1 7.2 7.3 7.4 7.5 7.6 . Microsoft.com. [June 10, 2019]. (原始内容存档于2019-07-02). 
  8. ^ 8.0 8.1 8.2 . Microsoft.com. [November 19, 2012]. (原始内容存档于2011-08-07). 
  9. ^ 9.0 9.1 9.2 . [October 29, 2010]. (原始内容存档于October 26, 2010). 
  10. ^ . Microsoft.com. [November 19, 2012]. (原始内容存档于2011-08-20). 
  11. ^ . [June 10, 2019]. (原始内容存档于2019-04-19). 
  12. ^ . Msdn.microsoft.com. [November 19, 2012]. (原始内容存档于2019-01-13). 
  13. ^ . Msdn.microsoft.com. [January 8, 2017]. (原始内容存档于2021-01-16). 
  14. ^ Update for Visual C++ 2013 Redistributable Package. [June 10, 2019]. 
  15. ^ . Msdn.microsoft.com. [June 12, 2016]. (原始内容存档于2016-07-17). 
  16. ^ . Msdn.microsoft.com. [June 12, 2016]. (原始内容存档于2016-08-22). 
  17. ^ . Msdn.microsoft.com. [June 28, 2016]. (原始内容存档于2017-10-21). 
  18. ^ . Msdn.microsoft.com. [August 28, 2016]. (原始内容存档于2018-10-11). 
  19. ^ MSDN TN062: Message Reflection for Windows Controls. [2017-08-01]. (原始内容于2017-08-01). 
  20. ^ 《CString 的部分实现剖析》
  21. ^ MSDN:Module States of a Regular DLL Dynamically Linked to MFC. [2016-06-30]. (原始内容于2017-05-27). 

微軟, 此条目的主題是微软基础类库, 关于与, 標題相近或相同的条目, 請見, 微软基础类库, 英語, microsoft, foundation, classes, 简称mfc, 是一个微软公司提供的类库, class, libraries, 以c, 类的形式封装了windows, 并且包含一个, 也是微软产品的唯一一个, 应用程序框架, 以减少应用程序开发人员的工作量, 其中包含的类包含大量windows句柄封装类和很多windows的内建控件和组件的封装类, 目录, 特性, 发展, mfc的优点, mfc的缺. 此条目的主題是微软基础类库 关于与 MFC 微軟 標題相近或相同的条目 請見 MFC 微软基础类库 英語 Microsoft Foundation Classes 简称MFC 是一个微软公司提供的类库 class libraries 以C 类的形式封装了Windows API 并且包含一个 也是微软产品的唯一一个 应用程序框架 以减少应用程序开发人员的工作量 其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类 目录 1 特性 2 发展 3 MFC的优点 4 MFC的缺点 5 第三方支持 6 版本 7 MFC的结构 7 1 应用程序启动 7 2 应用程序结束 7 3 消息循环与消息映射 7 3 1 消息分类 7 3 2 控件的通知消息与反射消息 7 3 3 消息传递处理机制 8 CString 9 支持MFC的DLL开发 10 常用头文件与库文件 11 参考和引用特性 编辑Visual C 包含MFC应用程序向导 可用于兼容MFC的应用程序 1 在ATL程序中也可以手动添加MFC支持 2 在向导中有各种选项以定制生成的程序的功能 例如界面风格 语种 数据库开发支持 打印支持 自动化支持 ActiveX支持 网络支持 基于HTML的帮助文档支持等等 在COM开发方面 相对于ATL来说 MFC的组件比较大 代码不够短小精悍 但是支持的功能也比较多 例如有对ActiveX Document的封装类 3 在界面开发方面 MFC提供对消息循环的封装 使用消息映射来避免虚函数的开销 MFC也提供常用Windows通用控件的封装类 MFC扩展DLL的接口使得MFC程序可以直接调用MFC扩展DLL中的MFC类 MFC也支持在标准DLL中被使用 发展 编辑MFC是在1992年随微软的Microsoft C C 7 0编译器发布的 用于面向16位元Windows的软件开发 起初 MFC是作为一个应用程序框架开发的 所以定名为Application Framework eXtensions AFX 4 随着 NET框架的发布 曾经一度被微软重点推荐的MFC被Visual Basic NET C Windows Forms抢走了不少市场份额 但是MFC继续在非托管软件开发中占据重要地位 在托管开发方面 MFC中也包括对Windows Forms和托管 非托管互操作的封装 微软在Windows Vista和Windows 7发布之后在MFC中增加了对新的Windows API支持 5 6 MFC的优点 编辑MFC的主要优点是可以用面向对象的方法来调用Windows API 以及能够更加便捷地开发应用程序 MFC将很多应用程序开发中常用的功能自动化 并且提供了文档框架视图结构和活动文档这样的便于自定义的应用程序框架 同时 在Visual C 内部也内建了很多对MFC的例如类向导这样的支持以减少软件开发的时间 使用类向导可以快速生成Hello World程序 MFC的缺点 编辑虽然MFC的源代码对用户是完全开放的 但是MFC的一些封装过程过于复杂 以致于新用户很难迅速掌握MFC的应用程序框架 以及在调试中定位问题的位置 同时 很多MFC对象不是线程安全的 致使在跨线程访问MFC对象时需要编写额外的代码 另外 MFC的很多类依赖于应用程序向导生成的代码 使得在使用Visual C 中其他类型的应用程序向导生成的工程中添加MFC支持的难度大大增加 第三方支持 编辑很多商用类库在MFC的基础上进一步实现了皮肤 渐变风格 多顶层窗口程序 属性列表等较受欢迎的功能 同时 在C 在线社区中 很大一部分开放的源代码也是基于MFC的 版本 编辑產品 程式庫 版本 發佈日期名稱 版本Microsoft C C 7 0 mafxcw lib MFC 1 0 1992Microsoft Visual C 1 0 Visual C 1 0 mfc200 dll MFC 2 0Visual C 1 5 mfc250 dll MFC 2 5Visual C 1 51 mfc250 dll MFC 2 51Visual C 1 52c mfc250 dll MFC 2 5 Windows 3 x 的最後發展平台 Microsoft Visual C 2 0 Visual C 2 0 mfc30 dll MFC 3 0Visual C 2 1 mfc30 dll MFC 3 1Visual C 2 2 mfc30 dll MFC 3 2Microsoft Visual C 4 0 Visual C 4 0 mfc40 dll MFC 4 0 mfc40 dll 包含於 Windows 95 1995年8月Visual C 4 1 mfc40 dll MFC 4 1Visual C 4 2 mfc42 dll MFC 4 2 mfc42 dll 包含於 Windows 98 初版 1998年3月內含於 Visual C 3 0 mfc42 dll MFC 4 2Microsoft Visual C 5 0 Visual C 5 0 mfc42 dll MFC 4 21 是 MFC 4 2 的主要更新Microsoft Visual C 6 0 Visual C 6 0 mfc42 dll MFC 6 0 1998年內含於 Visual C 4 0 mfcce400 dll MFC 6 0Microsoft Visual C NET 2002 Visual C NET 2002 Visual C 7 0 mfc70 dll MFC 7 0 2002年2月13日Microsoft Visual C NET 2003 Visual C NET 2003 Visual C 7 1 mfc71 dll MFC 7 1 2003年4月24日Visual C NET 2003 MS11 025 KB2465373 7 MFC 7 10 6119 0 2011年4月12日Microsoft Visual C 2005 Visual C 2005 Visual C 8 0 mfc80 dll 8 0 50727 42 2006年4月10日Visual C 2005 SP1 8 0 50727 762 2007年8月27日Visual C 2005 SP1 MS09 035 KB973544 8 9 8 0 50727 4053 2009年7月28日Visual C 2005 SP1 MS11 025 KB2467175 7 8 0 50727 5592 2011年4月12日Visual C 2005 SP1 MS11 025 KB2538242 7 10 8 0 50727 6195 包含於 redist 8 0 61000 8 0 61001 11 2011年6月14日Microsoft Visual C 2008 Visual C 2008 Visual C 9 0 mfc90 dll 9 0 21022 8 2007年11月19日Visual C 2008 MS09 035 KB973551 8 9 9 0 21022 218 2009年7月28日Visual C 2008 含Feature Pack 9 0 30411 2008年4月22日Visual C 2008 SP1 9 0 30729 1 2008年8月11日Visual C 2008 SP1 MS09 035 KB973552 8 9 9 0 30729 4148 2009年7月28日Visual C 2008 SP1 MS11 025 KB2467174 7 9 0 30729 5570 2011年4月12日Visual C 2008 SP1 MS11 025 KB2538243 7 9 0 30729 6161 安裝程式版本 9 0 30729 5677 2011年6月14日Microsoft Visual C 2010 Visual C 2010 Visual C 10 0 mfc100 dll 10 0 30319 1 2010年4月12日 12 Visual C 2010 MS11 025 KB2467173 7 10 0 30319 415 2011年4月12日Visual C 2010 SP1 10 0 40219 1 2011年3月10日Visual C 2010 SP1 MS11 025 KB2565063 7 10 0 40219 325 2011年8月9日Microsoft Visual C 2012 Visual C 2012 Visual C 11 0 mfc110 dll 11 0 50727 1 2012年9月12日Visual C 2012 Update 1 11 0 51106 1 2012年11月26日Visual C 2012 Update 3 11 0 60610 1 2013年6月26日Visual C 2012 Update 4 11 0 61030 0 2013年11月13日Microsoft Visual C 2013 Visual C 2013 Visual C 12 0 mfc120 dll 12 0 21005 1 2013年10月17日Visual C 2013 Update 2 12 0 30501 0 2014年5月12日Visual C 2013 Update 5 KB3138367 12 0 40649 5 2016年2月 Visual C 2013 Update 5 KB3179560 12 0 40660 0 2016年7月8日 13 Visual C 2013 Update 5 KB4032938 12 0 40664 0 2017年7月18日 14 Microsoft Visual C 2015 Visual C 2015 Visual C 14 0 mfc140 dll 14 0 23026 0 2015年7月20日Visual C 2015 Update 1 14 0 23506 0 2015年11月30日 15 Visual C 2015 Update 2 14 0 23918 0 2016年3月30日 16 Visual C 2015 Update 3 14 0 24210 0 2016年6月27日 17 Visual C 2015 Update 3 14 0 24212 0 2016年8月18日Visual C 2015 Update 3 KB3165756 14 0 24215 1 2016年9月15日 18 Microsoft Visual C 2017 Visual C 15 0 mfc140 dll 14 10 25008 0 2017年3月7日Visual C 15 1 14 10 25017 0 2017年4月5日 Visual C 15 2 14 11 25325 0 2017年5月10日Visual C 15 4 14 12 25810 0 2017年10月9日Visual C 15 6 14 13 26020 0 2018年3月5日Visual C 15 7 14 14 26405 0 2018年5月7日Visual C 15 7 3 14 14 26429 4 2018年5月31日Visual C 15 8 14 15 26706 0 2018年8月14日Visual C 15 9 14 16 27012 6 2018年11月13日Visual C 15 9 5 14 16 27024 1 2019年1月8日Visual C 15 9 6 14 16 27026 1 2019年1月24日Visual C 15 9 9 14 16 27027 1 2019年3月12日Visual C 15 9 15 14 16 27033 0 2019年8月13日Microsoft Visual C 2019 Visual C 16 0 0 mfc140 dll 14 20 27508 1 2019年4月2日 Visual C 16 1 0 14 21 27702 2 2019年5月21日Visual C 16 2 0 14 22 27821 0 2019年7月24日Visual C 16 3 0 14 23 27820 0 2019年9月23日Visual C 16 4 0 14 24 28127 4 2019年12月3日Visual C 16 5 0 14 25 28508 3 2020年3月16日Visual C 16 6 0 14 26 28720 3 2020年5月19日Visual C 16 6 3 14 26 28808 1 2020年7月30日Visual C 16 7 0 14 27 29016 0 2020年8月5日Visual C 16 7 5 14 27 29112 0 2020年9月29日Visual C 16 8 0 14 28 29325 2 2020年11月10日Visual C 16 8 2 14 28 29334 0 2020年11月19日Visual C 16 9 0 14 28 29910 0 2021年3月2日Visual C 16 9 2 14 28 29913 0 2021年3月16日Visual C 16 9 4 14 28 29914 0 2021年4月13日Visual C 16 10 0 14 29 30037 0 2021年5月25日Visual C 16 10 2 14 29 30038 0 2021年6月15日Visual C 16 10 4 14 29 30040 0 2021年7月20日Visual C 16 11 0 14 29 30133 0 2021年8月10日Visual C 16 11 4 14 29 30135 0 2021年10月5日Microsoft Visual C 2022 Visual C 17 0 0RC mfc140 dll 14 30 30704 0 2021年10月13日 1 Visual Studio速成版 Express 不包含MFC程式库 2 Feature Pack只用于英文版本的Visual Studio 2008 非英文版本的支援於将包含于Visual Studio 2008 Service Pack 1 MFC的结构 编辑作为一个应用程序的开发框架 必须满足各方面的功能需求 应用程序启动 编辑 基于MFC开发的应用程序在启动时 Windows操作系统 首先调用WinMain函数 位于appmodul cpp中 封装到mfc80 dll VS2005版 WinMain函数内调用了AfxWinMain函数 AfxWinMain函数 位于WinMain cpp中 调用了 该应用程序自定义的App类 这个类派生于CWinApp的 CWinApp又是派生于CWinThread 因此代表了应用程序的主线程 的InitInstance函数 该函数注册并创建窗口 通过AppUI2 cpp中的ProcessShellCommmand函数 然后ShowWindow UpdateWindow CWinThread的InitInstance函数 CWinThread的Run函数 位于thrdcore cpp中 该函数内部是Windows的消息循环 当应用程序收到WM QUIT消息后 CWinThread Run函数返回 紧接着CWinThread ExitInstance被调用 该函数可被覆盖 程序至此退出运行 消息循环是一个for 的死循环 该死循环内部包含了一个do while的循环结构 while循环条件是调用PeekMessage函数的返回值 如果当前UI线程消息队列为空就返回到外层的死循环 while循环体内做两件事 PumpMessage 实际调用AfxInternalPumpMessage函数实现其功能 GetMessage AfxPreTranslateMessage TranslateMessage DispatchMessage 即 从UI线程消息队列移除一条消息 遍历该消息的CWnd类直到该窗口的各级别父窗口的CWnd类以提供预处理该消息的机会 如果该消息是按键消息则翻译为WM CHAR消息 把该消息给相应的窗口函数 IsIdleMessage 实际调用了AfxInternalIsIdleMessage函数 对于WM PAINT WM SYSTIMER 以及光标位置没有变化的WM MOUSEMOVE或WM NCMOUSEMOVE 为Idle Message 各个窗口函数 WndProc 内部首先获取对应当前窗口句柄的CWnd类的指针 然后调用AfxCallWndProc函数 应用程序结束 编辑 如果是点击了IDOK按钮 默认是调用OnOK 然后是OnDestory 最后是PostNcDestroy 如果点击IDCANCEL按钮 默认调用OnCancel 然后是OnDestory 最后是PostNcDestroy 如果点击右上角的关闭按钮 先OnClose 然后是OnCancel 再然后是OnDestory 最后是PostNcDestroy 消息循环与消息映射 编辑 参见 Windows消息循环 nbsp MFC Class hierarchy for Windows message process flow消息分类 编辑 分类 消息 映射宏 消息处理函数原型 注释系统消息 标准Windows消息 MFC使用专用的相关的宏 如ON WM CREATE MFC使用专用的消息处理成员函数 一般地由窗口对象来处理这类消息命令消息 WM COMMAND ON COMMAND id memberFxn void OnXXX 通过标识符ID来区分来自哪个菜单项 工具栏按钮或者加速键等ON COMMAND RANGE id idLast memberFxn void OnXXX UINT id 批量处理一定范围内的标示符IDON UPDATE COMMAND UI id idLast memberFxn void OxXXX CCmdUI pCmdUI 程序空闲时发的界面更新消息的宏ON UPDATE COMMAND UI RANGE id idLast memberFxn void OxXXX CCmdUI pCmdUI ON CONTROL id idLast memberFxn void OnXXX 父窗口响应控件发送的消息ON CONTROL RANGE id idLast memberFxn void OnXXX UINT id ON CONTROL REFLECT id idLast memberFxn void OnXXX 子控件响应父窗口反射回来的通知消息通知消息WM NOTIFY ON NOTIFY wNotifyCode id memberFxn afx msg void memberFxn NMHDR pNotifyStruct LRESULT result wParam为控件ID lParam指向NMHDR结构体 结构体的code域值为控件通知码用来表示控件上的动作 如NM CLICK 一般地由父窗口对象来处理这类消息 ON NOTIFY RANGE wNotifyCode id idLast memberFxn 可手工添加 class wizard不支持 处理控件id连续的一批控件的同一通知码消息 ON NOTIFY EX 允许通知消息在多处被处理ON NOTIFY EX RANGEON NOTIFY REFLECT afx msg void memberFxn NMHDR pNotifyStruct LRESULT result 复杂子控件响应父窗口反射回来的通知消息自定义消息 窗口类内部自定义消息WM USER到WM APP 1 ON MESSAGE 消息名 memberFxn afx msg LRESULT OnMyMessageXXX WPARAM wParam LPARAM lParam 示例程序内部自定义消息WM APP到0xBFFF ON THREAD MESSAGE WM THREADMSG OnThreadMessage afx msg void OnThreadMessage WPARAM wParam LPARAM lParam 示例ON REGISTERED THREAD MESSAGE afx msg void OnMyRegisterdThreadMsg WPARAM LPARAM RegisterWindowMessage 使用一个字符串来登记一个自定义的消息ID应用程序之间自定义消息0xC000到0xFFFF ON REGISTERED MESSAGE LRESULT OnMyMessageXXX WPARAM wParam LPARAM lParam RegisterWindowMessage 使用一个字符串来登记一个自定义的消息ID 便于跨进程应用控件的通知消息与反射消息 编辑 窗体上的控件 应当向父窗体通报控件发生的各种事件 如被点击 绘制 内容改变等等 称为通知消息 notification message 在 Windows 3 x的16位程序设计时代 控件向父窗体发送WM COMMAND消息 由父窗体的代码负责实现这些事件 其中wParam的低16位是 control ID 高16位是notification code 例如BN CLICKED lParam是控件句柄 因此 再无可能传递其它信息给父窗体 为此 为传递具有特别内容的控件事件 Windows 3 x定义了一批特殊的通知消息 notification messages WM PARENTNOTIFY 子窗口的某些重大事件发生时通知父窗口 包括创建 销毁 鼠标各键按下等事件 子窗口的滚动情况的通知消息 WM VSCROLL WM HSCROLL 子窗口的绘制通知消息 WM DRAWITEM WM MEASUREITEM WM COMPAREITEM WM DELETEITEM WM CHARTOITEM WM VKEYTOITEM WM CTLCOLOR 设置按钮 编辑框 ListBox Static 滚动条控件与MessageBox DialogBox的前景色 背景色 背景模式 字体 并返回一把Brush 用于控件背景绘制 早于4 0版本的MFC 在控件类提供了虚函数处理这些通知消息 这一办法已经被下述的 消息反射 取代 但仍然向后兼容继续支持 随着Windows 95开始了32位程序时代 伴之而来的是Win32 API 与 MFC 4 0 Win32增加了很多复杂的控件 需要使用更多的通知消息传递很多复杂的数据给父窗体 Win32 API仅仅增加了一个消息WM NOTIFY 就实现了这些功能 lParam参数开头是NMHDR数据结构 其后是与该通知类型相关的特定数据结构 typedef struct tagNMHDR HWND hwndFrom UINT idFrom UINT code NMHDR CWnd OnNotify函数处理通知消息 它的默认实现是检查消息映射表 message map 查找通知的处理器函数并调用 一般说来 不必覆盖OnNotify 而应该写一个处理器函数并增加为该窗口类的消息映射表条目 ON NOTIFY wNotifyCode id memberFxn 成员函数应该写为 afx msg void memberFxn NMHDR pNotifyStruct LRESULT result MFC 4 0提供了一种特性 消息反射 message reflection 19 允许控件通知消息既可以在父窗口中 也可以在控件中被处理 可以对控件创建一个派生的控件类 实现对从父窗口反射回来的指定类型消息的处理 消息反射是MFC而不是Win32的特性 因此父窗口的类必须是从CWnd派生 从而父窗口在CWnd OnNotify函数中处理控件的WM NOTIFY时 首先调用CWnd ReflectLastMsg把消息反射回控件的CWnd SendChildNotifyLastMsg函数去处理 ReflectLastMsg返回值就是在控件的消息映射中使用ON NOTIFY REFLECT EX 声明的反射消息处理函数的返回值 可以通知父窗口该消息是否已经被控件处理 控件的CWnd SendChildNotifyLastMsg函数 首先获得线程的最后一条message 然后调用发送窗口的虚函数OnChildNotify函数 在子窗口处理反射回来的控件消息 第一种方法是重载控件窗口的OnChildNotify虚函数 第二种办法是由CWnd OnChildNotify默认处理去调用CWnd ReflectChildNotify函数 进入控件子窗口的MFC消息映射的标准处理 子窗口处理的消息被译成WM REFLECT BASE WM NOTIFY消息 对于WM NOTIFY 仅当在控件的消息映射 message map 中 控件没有通过ON NOTIFY REFLECT 声明的反射消息处理函数 父窗口的相应的通知消息处理函数才会被调用 在父窗口消息映射中使用宏ON NOTIFY声明 控件中通过ON NOTIFY REFLECT EX 声明的反射消息处理函数可以返回真或假 以决定父窗口是否继续处理该通知消息 WM NOTIFY以外的其它通知消息 父窗口在第一时间有机会处理它 控件对它的处理排在第二位 反射消息处理函数通常使用特定的名字 对应的消息反射宏的名字是在消息名字加上前缀ON 后缀 REFLECT 如WM CTLCOLOR对应ON WM CTLCOLOR REFLECT 但以下三种情况 反射消息处理函数可以随意自行起名 对应的消息反射宏的名字分别为 WM COMMAND使用ON CONTROL REFLECT WM NOTIFY使用ON NOTIFY REFLECT ON UPDATE COMMAND UI使用ON UPDATE COMMAND UI REFLECT消息传递处理机制 编辑 MFC类体系中 Windows消息传递处理机制是基于CCmdTarget类及其派生类的静态成员函数GetThisMessageMap 内部定义的静态数据成员 成员类型为AFX MSGMAP ENTRY的数组 messageEntries 在类的实现文件中 在BEGIN MESSAGE MAP与END MESSAGE MAP之间的内容来初始化消息映射入口项数组 数据类型为AFX MSGMAP的变量messageMap 该结构包含两项 分别是直接基类GetThisMessageMap函数指针与本类的 messageEntries数组首元素地址 在头文件的类定义中使用宏DECLARE MESSAGE MAP 来声明静态成员函数GetThisMessageMap与虚函数GetMessageMap用户所写的类的Windows消息处理函数 例如OnCommand 必须转换为CCmdTarget 的成员函数指针类型AFX PMSG 保存在该类的 messageEntries数组中 struct AFX MSGMAP ENTRY UINT nMessage windows消息代号 UINT nCode WM NOTIFY的控制代码 UINT nID WM COMMAND下面的ID号 如果为其他的消息 则这个数字为0 UINT nLastID 和前面的ID一起组成一个范围 用于发送一次消息 处理执行多次 UINT nSig 标志消息处理函数的类型 AFX PMSG pfn 函数调用指针 typedef void CCmdTarget AFX PMSG void 调用用户类中该消息处理函数时 根据该函数保存在 messageEntries中的signature 一个无符号整型表示的函数的形参类型列表与返回值类型 把类型为void CCmdTarget AFX PMSG void 的成员函数指针强制转为其它类型的CCmdTarget成员函数指针 例如void AFX MSG CALL CWnd pfn v i i int int 目前在union MessageMapFunctions中列出了近百种CCmdTarget成员函数指针 然后调用转换后的成员函数指针 这是基于Visual C 编译器把单继承的成员函数指针编译为只保存了函数的内存起始地址 因此可以在同一个单继承类中把一种类型的成员函数指针强制转换为另一种成员函数指针 或者把单继承派生类的成员函数指针强制转换为基类成员函数指针 这是打破了C 标准的违例办法 例如 对于CWnd OnCommand函数 转换过程是 BOOL CWnd WPARAM LPARAM lParam gt void CWnd gt void CCmdTarget CString 编辑CString是MFC中最常见的类之一 用于封装字符串数据结构 它只有一个数据成员m pszData 其值为字符串的首地址 其数据类型为wchar t 或char 在CString的m pszData的前面实际还分配了CSringData数据块 包含了管理数据 IAtlStringMgr pStringMgr int nDataLength int nAllocLength int nRefs 自底向上 CAtlStringMgr提供内存管理 CStringData提供共享管理 CString提供字符串操作 CAtlStringMgr的一个成员是IAtlMemMgr接口 这是策略模式 可以引用某个内存管理类 CAtlStringMgr的另一个成员是CNilStringData 因此 每次为CString动态分配地址空间 实际分配长度为 nChars 1 nCharSize sizeof CStringData 通过 Attach 操作 将这个 CStringData 与 CSimpleStringT m pszData 执行了关联 当执行CString的默认构造函数生成一个空串时 实际上都是构造一个CnilStringData对象 CNilStringData 派生自 CStringData 额外拥有一个 achNil 的数组成员 这个数组初始化为空字符串 通过这个 achNil 保证了一个经过调用默认构造函数初始化的 CString 其指向的真正的字符串是一个空串 部分编译器对std string放弃了写时复制 Copy On Write 机制 但是 CString一直采取这一机制 CSimpleStringT Fork 函数就提供了这样一个操作 具体分为下面几步 根据传入的一个长度分配一段新的空间 Allocate nLength 把旧数据拷贝到新的空间里面 CopyChars 旧数据块的引用技术减1 pOldData gt Release 把 m pszData 和新的数据块关联起来 Attach pNewData GetString方法返回的是只读的字符串地址 而GetBuffer方法返回的是可写的字符串地址 如果数据区是共享的 则写时复制 如果修改了字符串内容 这时需要调用ReleaseBuffer方法把新的字符串长度修改到元数据中 并在尾部增加2个0字节 20 CString对象用作可变参数函数 如printf 的实参时 由于无法通过形参类型确定调用哪个CString的类型转换操作符函数 因此有必要显式指明要转换的类型 如果需要在函数的参数传递CString 由于CString使用了引用计数 因此函数参数传递一个CString对象是可行的 不需要修改其内容时 推荐使用const CString amp 支持MFC的DLL开发 编辑使用Visual C 可以开发3种DLL 不使用MFC的DLL 使用MFC的规则的DLL 输出的函数不涉及MFC 因此可以被支持 不支持MFC的应用程序调用该DLL 动态链接到MFC Regular DLLs dynamically linked to MFC 静态链接到MFC Regular DLLs statically linked to MFC 使用MFC的扩展DLL Extension DLLs 只能动态链接到MFC 输出的函数涉及MFC 也可以输出基于MFC的派生类 由于DLL与调用它的应用程序都可以有自己的MFC全局数据与句柄映射 handle mapping 如果句柄值相同 则默认使用应用程序的映射到的资源 为了不互相干扰 允许DLL内部使用自己的资源 必须在DLL函数的入口处把资源模块句柄从默认的应用程序切换为该DLL 办法是 在该DLL的每个输出的函数的最开始之处调用AFX MANAGE STATE AfxGetStaticModuleState 21 函数AfxGetStaticModuleState的功能是在运行栈上创建一个AFX MODULE STATE类的实例 对其进行设置 函数返回值为AFX MODULE STATE的指针 AFX MODULE STATE类利用其构造函数和析构函数进行模块状态现场存储及恢复 使用AfxGetResourceHandle 获取当前资源模块句柄 使用AfxSetResourceHandle HINSTANCE xxx 设置程序要使用的资源模块句柄 常用头文件与库文件 编辑STDAFX H 载入其他MFC头文件 AFXWIN H 它和它载入的文件声明了所有的MFC类 其内包含AFX H 后者包含了AFXVER H 后者又载入了AFXV W32 H 后者又载入WINDOWS H AFXEXT H 使用工具栏 状态栏的程序必须载入这个文件 AFXDLGS H 通用对话框 Common dialog 的MFC程序需要载入此文件 它内部包含COMMDLG H FXCMN H 通用控件 common control 的MFC程序需要载入此文件 AFXCOLL H 使用MFC提供的容器都需要载入此文件 AFXDLLX H 凡使用MFC extension DLLs需要载入此文件 AFXRES H MFC程序的RC文件必须载入此文件 此文件中对于标准资源的ID都有默认值 它们定义于此文件中 参考和引用 编辑 MFC应用程序向导 2011 05 18 原始内容存档于2016 04 02 HOWTO 给ATL项目添加MFC支持 2010 03 06 原始内容存档于2015 03 11 Recommendations for Choosing Between ATL and MFC 页面存档备份 存于互联网档案馆 英文 Upgrading Relational Databases with Objects Robert Vermeulen著 126页 MFC Updates for Vista Common Controls 2010 03 06 原始内容存档于2010 03 27 Making your application sparkle with Windows 7 2010 03 06 原始内容存档于2010 03 28 7 0 7 1 7 2 7 3 7 4 7 5 7 6 MS11 025 Vulnerability in Microsoft Foundation Class MFC Library could allow remote code execution April 12 2011 Microsoft com June 10 2019 原始内容存档于2019 07 02 8 0 8 1 8 2 Microsoft Security Bulletin MS09 035 Moderate Vulnerabilities in Visual Studio Active Template Library Could Allow Remote Code Execution 969706 Microsoft com November 19 2012 原始内容存档于2011 08 07 9 0 9 1 9 2 Protect your computer from the Active Template Library ATL security vulnerability October 29 2010 原始内容存档于October 26 2010 Microsoft Visual Studio 2005 Service Pack 1 MFC Security Update Microsoft com November 19 2012 原始内容存档于2011 08 20 Where can I download Visual C Redistributables June 10 2019 原始内容存档于2019 04 19 Visual C Exploring New C and MFC Features in Visual Studio 2010 Msdn microsoft com November 19 2012 原始内容存档于2019 01 13 Update for Visual C 2013 and Visual C Redistributable Package Msdn microsoft com January 8 2017 原始内容存档于2021 01 16 Update for Visual C 2013 Redistributable Package June 10 2019 Visual Studio 2015 Update 1 Msdn microsoft com June 12 2016 原始内容存档于2016 07 17 Visual Studio 2015 Update 2 Msdn microsoft com June 12 2016 原始内容存档于2016 08 22 Visual Studio 2015 Update 3 Msdn microsoft com June 28 2016 原始内容存档于2017 10 21 Microsoft Visual Studio 2015 Update 3 KB3165756 Msdn microsoft com August 28 2016 原始内容存档于2018 10 11 MSDN TN062 Message Reflection for Windows Controls 2017 08 01 原始内容存档于2017 08 01 CString 的部分实现剖析 MSDN Module States of a Regular DLL Dynamically Linked to MFC 2016 06 30 原始内容存档于2017 05 27 ATL Microsoft Visual Studio Visual Studio NET Object Windows Library 取自 https zh wikipedia org w index php title MFC 微軟 amp oldid 75422007, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。