1. 程式人生 > >MFC自動生成程式碼詳解(一)

MFC自動生成程式碼詳解(一)

首先宣告這篇部落格是給MFC剛剛上路的coder準備的,老鳥們就自覺無視我吧!

大家有沒有感覺,建立MFC工程時他總會生成一大堆檔案一大堆程式碼。雖然給我們帶來了便利,但是除錯的時候碰到這些程式碼總是畏首畏腳的,從來不敢動他們。這篇部落格就來幫大家解決這個問題。讓你在熟悉他們的作用同時,真正的不怕他們!

現在我見了一個工程名字為Example他會生成以上幾個檔案


我們就從從Example.cpp開始,先看最中間的

CExampleApp theApp; //application object
這段程式碼其實就是本程式的application object,每個程式有且僅有一個。當程式執行時,這個全域物件產生,構造是執行起來。CWinApp 之中的成員變數將因為theApp 這個全域物件的誕生而獲得配置與初值。此段執行完後winmain登場,由於winmain並不在這幾個檔案夾了,所以不能直觀的看到他。
int AFXAPI AfxWinMain (...)
{
CWinApp* pApp = AfxGetApp();
AfxWinInit(...);
pApp->InitApplication();
pApp->InitInstance();
nReturnCode = pApp->Run();
AfxWinTerm();
}

theapp獲得初值後,上面的程式碼開始執行。至於上面幾個函式具體的程式碼實現會在後面的連載中一一介紹,在這裡先交待一下他們的作用。
AfxWinInit(...);

這句程式碼的意思借用《深入淺出MFC》的一句話,。MFC中的 AfxWinInit的確會為我們註冊四個視窗類別,但不再是在AfxWinInit 中完成。

pApp->InitApplication();
本段程式碼相當於CMyWinApp::InitApplication();CMyWinApp 繼承自CWinApp,而InitApplication 又是CWinApp 的一個虛擬函式;我們並沒有改寫它(大部份情況下不需改寫它),所以上述動作相當於呼叫:CWinApp::InitApplication();這些動作都是MFC 為了內部管理而做的。
pApp->InitInstance();
這段程式碼和上面的程式碼一樣,也相當於呼叫CMyWinApp::InitInstance();但是看下面的Example.cpp中的InitInstance()被我們改寫了,所以說上述動作的的確確就是呼叫我們自己(CMyWinApp)的這個InitInstance 函式。我們將在該處展開我們的主視窗生命。
nReturnCode = pApp->Run();
此時程式會執行Example.cpp中的InitInstance(),所以上面的run()函式我們先跳過。
#include "stdafx.h"
#include "Example.h"
#include "ExampleDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CExampleApp

BEGIN_MESSAGE_MAP(CExampleApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CExampleApp 構造

CExampleApp::CExampleApp()
{
	// TODO: 在此處新增構造程式碼,
	// 將所有重要的初始化放置在 InitInstance 中
}


// 唯一的一個 CExampleApp 物件

CExampleApp theApp;


// CExampleApp 初始化

BOOL CExampleApp::InitInstance()
{

程式剛好執行的上面一句我們很多初始化都寫在這個函式裡,包括建立類物件,m_pMainWnd->ShowWindow(m_nCmdShow);  m_pMainWnd->UpdateWindow();兩個函式這樣再加上建構函式中的Create()函式,我的的視窗就這樣生成了。很簡單吧!

nReturnCode = pApp->Run();
下面就到這段程式碼的了。MFC的訊息機制也從這開始了。在上面視窗建立完之後訊息佇列中出現了一個WM_PAINT 訊息,等待被處理。現在,執行的腳步到達pApp->Run。當然Run()和上面一樣相當於CMyWinApp::Run();而Run 又是CWinApp 的一個虛擬函式。所以說他和initapplicationa()一樣。執行的這裡下面就是MFC的精髓所在了。MFC 提供給應用程式使用的「很方便的介面」是兩組巨集。以Hello 的主視窗為例,

第一個動作是在Example.H 加上DECLARE_MESSAGE_MAP:

DECLARE_MESSAGE_MAP()

下一個動作就用到Example.cpp中的一組巨集

BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_PAINT()
ON_COMMAND(IDM_ABOUT, OnAbout)
END_MESSAGE_MAP()

這樣訊息WM_PAINT 就順利匯入導到OnPaint 函式中了。但是他最後怎麼到他需要的函式中去的呢?這就是MESSAGE_MAP()的作用了。在這裡先不詳談。

下面就到下一個檔案ExampleDlg.cpp了

class CExampleDlg : public CDialog
{
// 構造
public:
	CExampleDlg(CWnd* pParent = NULL);	// 標準建構函式

// 對話方塊資料
	enum { IDD = IDD_EXAMPLE_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支援


// 實現
protected:
	HICON m_hIcon;

	// 生成的訊息對映函式
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
};

看到註釋相信大家對這段程式碼已經有了基本的瞭解了,在這其中是一些函式的宣告包括建構函式,訊息對映函式,和非常重要的用於資料動態繫結的DoDataExchange()接下來我們來看ExampleDlg.cpp

BOOL CExampleDlg::OnInitDialog()
{
	
}
void CExampleDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	
}

// 如果向對話方塊新增最小化按鈕,則需要下面的程式碼
//  來繪製該圖示。對於使用文件/檢視模型的 MFC 應用程式,
//  這將由框架自動完成。

void CExampleDlg::OnPaint()
{
}
cpp檔案是對.h檔案的函式的實現在這裡就不全部copy過來的,在這隻介紹最重要的三個函式
BOOL CExampleDlg::OnInitDialog()
呼叫這個成員函式是對WM_INITDIALOG訊息作出的反應。如果在對話方塊初始化後需要執行特別處理,覆蓋覆蓋該函式。首先呼叫基類OnInitDialog,但不考慮其返回值。正常情況下,覆蓋的函式返回TRUE。呼叫是通過標準的全域性對話方塊過程,而不是通過訊息對映。因此該函式不需要訊息對映入口。
void CExampleDlg::OnSysCommand(UINT nID, LPARAM lParam)

這個函式主要是截獲控制命令的

void CExampleDlg::OnPaint()

OnPaint()是CWnd的類成員,負責響應WM_PAINT訊息。

下面就到了stdafx了

// stdafx.h : 標準系統包含檔案的包含檔案,
// 或是經常使用但不常更改的
// 特定於專案的包含檔案

#pragma once

#ifndef _SECURE_ATL
#define _SECURE_ATL 1
#endif

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN		// 從 Windows 頭中排除極少使用的資料
#endif

// 如果您必須使用下列所指定的平臺之前的平臺,則修改下面的定義。
// 有關不同平臺的相應值的最新資訊,請參考 MSDN。
#ifndef WINVER				// 允許使用特定於 Windows XP 或更高版本的功能。    下面這段程式碼相信大家看註釋就能明白,那就是本程式對版本的要求
#define WINVER 0x0501		// 將此值更改為相應的值,以適用於 Windows 的其他版本。
#endif

#ifndef _WIN32_WINNT		// 允許使用特定於 Windows XP 或更高版本的功能。
#define _WIN32_WINNT 0x0501	// 將此值更改為相應的值,以適用於 Windows 的其他版本。
#endif						

#ifndef _WIN32_WINDOWS		// 允許使用特定於 Windows 98 或更高版本的功能。
#define _WIN32_WINDOWS 0x0410 // 將它更改為適合 Windows Me 或更高版本的相應值。
#endif

#ifndef _WIN32_IE			// 允許使用特定於 IE 6.0 或更高版本的功能。
#define _WIN32_IE 0x0600	// 將此值更改為相應的值,以適用於 IE 的其他版本。值。
#endif

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// 某些 CString 建構函式將是顯式的

// 關閉 MFC 對某些常見但經常可放心忽略的警告訊息的隱藏
#define _AFX_ALL_WARNINGS

#include <afxwin.h>         // MFC 核心元件和標準組件                                            下面的程式碼主要用來引用MFC各元件和類
#include <afxext.h>         // MFC 擴充套件


#include <afxdisp.h>        // MFC 自動化類



#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>		// MFC 對 Internet Explorer 4 公共控制元件的支援
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>			// MFC 對 Windows 公共控制元件的支援
#endif // _AFX_NO_AFXCMN_SUPPORT

最後就剩下stdafx.cpp了,這段程式碼大家註釋簡單明瞭,在這裡就不做過多解釋了!

// stdafx.cpp : 只包括標準包含檔案的原始檔
// Example.pch 將作為預編譯頭
// stdafx.obj 將包含預編譯型別資訊

#include "stdafx.h"

看了這麼半天相信你對自動生成的程式碼已經有了一定的瞭解了吧!你是否找到編寫MFC的樂趣了呢?如果是的,那就關注一下我吧!讓我們一起學習,一起成長!