Windows Programming/Microsoft Foundation Classes

微软基类库(MFC)是一套包装了Windows API的简洁的C++类库,用于Microsoft Visual Studio开发Windows应用程序。

如果没有下述需求,你可以考虑采取Win32 API SDK或其他包装库:

  1. 利用复杂的GUI,使用文档/视图架构或者复杂的控件。
  2. 使用依赖于MFC的其他库
  3. 你的应用程序使用复杂安装

MFC 与 C++

编辑

MFC类库不使用多继承。 大多数MFC类派生自CObject,使用多继承会造成歧义。参见Using C++ Multiple Inheritance with MFC (msdn.microsoft.com) 以避开这一限制。

MFC Conventions

编辑

MFC使用驼峰式大小写匈牙利命名法

使用MFC

编辑

必须包括MFC标准头文件<afxwin.h>。其它头文件是<afxext.h> (MFC extensions), <afxcmn.h> ( MFC common对话框)。

stdafx.h

编辑

stdafx.h是MFC项目中的标准预编译头文件。

theApp

编辑
extern CYourAppClass theApp;

放在你的需要使用应用程序类的头文件中。

AfxGetApp'函数返回theApp指针。例如:

class CMyDialog : public CDialog 
{ 

  // other class stuff here... 
  
  // Attributes 
  public: 
    CMdiApp* m_pApp; 
};

记住,初始化m_pAppNULL指针值。

CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/): CDialog(CMyDialog::IDD, pParent) 
{ 
           //{{AFX_DATA_INIT(CMyDialog) 
           //}} AFX_DATA_INIT 
           // Outside the special-format comments above... 
           m_pApp = (CMdiApp*)AfxGetApp( ); 
}

可以使用:

m_pApp->m_nMemberVar; 
m_pApp->MemberFunction(nParam1, strParam2);

一个基本的MFC程序例子

编辑

这个例子显示一个窗口,但不处理任何输入。

#include <afxwin.h>  //basic MFC include
 
//class derived from CFrameWnd, which is derived from CWnd
class Basic_Window:public CFrameWnd
{
   public:
       Basic_Window()
       {
            Create(NULL, "Basic MFC Window");
            // In some cases you might want to use
            // Create(NULL, _T(":Basic MFC Window"));
       }
};
 
//class derived from CWinApp, which is the main instance of our application
class MyProgram:public CWinApp
{
      //a pointer to our window class object
      Basic_Window *bwnd; 
   public:
 
      //this is essentially our "entry point"
      BOOL InitInstance()
      {
           bwnd = new Basic_Window();
           m_pMainWnd = bwnd;
           m_pMainWnd->ShowWindow(1);
           return 1;
      }
};
  
//the program class instance pointer
MyProgram theApp;


全局变量

编辑

例如 m_pMainWnd

干净地关闭MFC应用程序

编辑

对话框退出调用什么函数主要看你按哪个按钮退出。一般就三种情况:

  1. 点击IDOK按钮退出:先调用OnOK(),然后是OnDestory(),最后是PostNcDestroy()
  2. 点击IDCANCEL按钮退出:先调用OnCancel(),然后是OnDestory(),最后是PostNcDestroy()
  3. 点击右上角的关闭按钮退出:先OnClose(),然后是OnCancel(),再然后是OnDestory() ,最后是PostNcDestroy()

在单视图程序中,根据<<深入浅出MFC>>所讲,程序退出时执行的操作顺序为 (1)用户点击退出按钮,发送了WM_CLOSE消息 (2)在WM_CLOSE消息的处理函数中,调用DestroyWindow() (3)在DestroyWindow()中发送了WM_DESTROY消息、发送WM_NCDESTROY;如果含有子窗口,DestroyWindow()会向子窗口发送WM_DESTROY和WM_NCDESTROY消息。 (4)在WM_DESTROY消息中调用PostQuitMessage(),发送WM_QUIT消息,结束消息循环 (5)WM_NCDESTROY对应的消息处理函数是OnNcDestroy,最后会调用PostNcDestroy。PostNcDestroy经常被用户重载以提供释放内存操作。例如可以使用delete this;

CView::PostNcDestroy中唯一的操作就是delete this;CframeWnd::PostNcDestory也是如此。而默认的CWnd::PostNcDestroy是空操作,CDialog中也没有对其进行重载,即也是空。

综上,程序先调用OnClose()(也可能不调用),然后调用OnDestroy()(必调用),所以,如果要进行程序结束时的清理工作,应该在OnDestroy()中,而不是在OnClose(),否则就有可能会出现内存泄漏的危险了!

一般方法是调用PostQuitMessage([exit code]);,但需要注意应该释放各种资源。调用AfxGetMainWnd()->PostMessage( WM_CLOSE );在一些情况下是更好的方法,它会出发正确地关闭序列。特别是对于MDI/SDI应用程序来说。

用户登录对话框

编辑

在显示主窗口之前显示一个模式对话框来提示用户登录一个常用的功能。只需要在PreCreateWindow函数中加入显示对话框的代码就可以完成这个功能。

忙等待外观的鼠标指针

编辑

在执行一个函数时显示忙等待的鼠标指针,MFC提供了一个帮助类:CWaitCursor作为局部变量:

CWaitCursor aWaitCursor;

线程

编辑

工作线程:AfxBeginThread()

GUI线程:

读写文件

编辑

流式文件是被缓冲的。

CFile是MFC文件类的基类,它直接提供非缓冲的二进制磁盘输入/输出设备,通过派生类支持文本文件和内存文件。

CStdioFile继承自CFile。CStdioFile不支持Duplicate,LockRange,和UnlockRange这几个CFile函数。如果在CStdioFile中调用了这几个函数,将会出现CNoSupported异常。CStdioFile定义了ReadString与WriteString两个成员函数,注意二者都做了\n与\r\n的自动转换。

  • CStdioFile::ReadString(LPTSTR lpsz, UINT nMax);读取一行文本到缓冲区,遇到“0x0D 0x0A”时停止读取,并且去掉硬回车“0x0D”,保留换行符“0x0A”,在字符串末尾添加“\0”(0x00)。nMax个字符里包含0x00这个字符。如果缓冲区容量不够,则没有换行符“0x0A”。如果文件未读完返回true,否则返回false。
  • CStdioFile::ReadString(CString &rString); 重载版本。读取一行文本到rString,遇到回车换行符停止读取。回车和换行符不读到rString。
  • CStdioFile::WriteString( LPCTSTR lpsz );(不支持CString直接写入)结束的空字符(“\0”)不被写入该文件。lpsz中的所有换行符都被以一个硬回车换行符对写入该文件,即“\n”被转化成“\r\n”写入到文件里。