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」寫入到文件里。