VC++學習日誌 MFC基礎

CWnd類封裝了所有與窗口操作相關的操作

WinMain函數,它是所有程序的入口函數,在MFC中找不到,但是在鏈接的時候編譯器將他鏈接到我們的程序中,那麼在程序中如何找到呢?

首先搜索(z):\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc(當然是你的anzhaung目錄)下面搜索文件中包含WinMain的文件,會找到appmodul.cpp,然後雙擊打開,可以使用VS打開,會找到WinMain函數。斷點調試可以發現程序確實鏈接了:_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, __in LPTSTR lpCmdLine, int nCmdShow){ // call shared/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}注意上面的_tWinMain是一個宏,展開還是wWinMain

CMainFrame類名稱是不會變得。其他根據工程名加表示特徵後綴。在MFC中所遇的類都以C開頭。

打開CTestApp類,發現它是從CWinApp派生來的,CWinApp表示一個應用程序類。在類試圖中選中CTestApp類,在下面選擇它的構造函數,如下:CTestApp::CTestApp(){ // TODO: 在此處添加構造代碼, // 將所有重要的初始化放置在 InitInstance 中}// 唯一的一個 CMFC2App 對象

CTestApp theApp;

可以設置斷點,調試,發現程序會首先執行這裏,然後在執行WinMain函數的斷點處。因爲設置了一個CTestApp的全局變量:theApp,可以設置斷點調試,程序會首先執行CTestApp theApp;,然後進入構造函數,然後才進入WinMain函數。這點很重要!全局對象和變量都是在入口函數之前分配內存空間。那麼在這裏CTestApp theApp;爲什麼要定義這樣一個全局對象呢?在一個MFC程序中只能有一個從CWinApp派生來的類,也只能有一個該類的對象。它表示了應用程序本身。基於MFC的應用程序中,使用WinApp對象來表示一個唯一的應用程序。正因爲定義了一個全局對象,所以在程序執行之前就要進行初始化CTestApp類的構造函數,要構造子類的構造函數,會激發父類的構造函數,所以導致了CWinApp的構造函數。因此把派生類和基類關聯起來了。同樣,我們依然在剛纔的路徑下搜索“CWinApp”,會找到appcore.cpp,雙擊打開。可以找到CWinApp的構造函數,CWinApp::CWinApp(LPCTSTR lpszAppName){...............}注意:這裏的構造函數包含一個參數,可是我們在子類中的定義並沒有參數,原因我們可以將鼠標放到CWinApp上右鍵,轉到定義,會發現:CWinApp(LPCTSTR lpszAppName = NULL);這樣一個缺省值爲NULL的定義。所以子類可以不用傳遞這個參數。

接下來看下完整的CWinApp構造函數:

CWINAPP::CWINAPP(LPCTSTR LPSZAPPNAME)
{
 IF (LPSZAPPNAME != NULL)
  M_PSZAPPNAME = _TCSDUP(LPSZAPPNAME);
 ELSE
  M_PSZAPPNAME = NULL;
 // INITIALIZE CWINTHREAD STATE
 AFX_MODULE_STATE* PMODULESTATE = _AFX_CMDTARGET_GETSTATE();
 ENSURE(PMODULESTATE);
 AFX_MODULE_THREAD_STATE* PTHREADSTATE = PMODULESTATE->M_THREAD;
 ENSURE(PTHREADSTATE);
 ASSERT(AFXGETTHREAD() == NULL);
 PTHREADSTATE->M_PCURRENTWINTHREAD = THIS;
 ASSERT(AFXGETTHREAD() == THIS);
 M_HTHREAD = ::GETCURRENTTHREAD();
 M_NTHREADID = ::GETCURRENTTHREADID();
 // INITIALIZE CWINAPP STATE
 ASSERT(AFXCURRENTWINAPP == NULL); // ONLY ONE CWINAPP OBJECT PLEASE
 PMODULESTATE->M_PCURRENTWINAPP = THIS;
 ASSERT(AFXGETAPP() == THIS);
 // IN NON-RUNNING STATE UNTIL WINMAIN
 M_HINSTANCE = NULL;
 M_HLANGRESOURCEDLL = NULL;
 M_PSZHELPFILEPATH = NULL;
 M_PSZPROFILENAME = NULL;
 M_PSZREGISTRYKEY = NULL;
 M_PSZEXENAME = NULL;
 M_PRECENTFILELIST = NULL;
 M_PDOCMANAGER = NULL;
 M_ATOMAPP = M_ATOMSYSTEMTOPIC = NULL;
 M_LPCMDLINE = NULL;
 M_PCMDINFO = NULL;
 // INITIALIZE WAIT CURSOR STATE
 M_NWAITCURSORCOUNT = 0;
 M_HCURWAITCURSORRESTORE = NULL;
 // INITIALIZE CURRENT PRINTER STATE
 M_HDEVMODE = NULL;
 M_HDEVNAMES = NULL;
 M_NNUMPREVIEWPAGES = 0;     // NOT SPECIFIED (DEFAULTS TO 1)
 // INITIALIZE DAO STATE
 M_LPFNDAOTERM = NULL;   // WILL BE SET IF AFXDAOINIT CALLED
 // OTHER INITIALIZATION
 M_BHELPMODE = FALSE;
 M_EHELPTYPE = AFXWINHELP;
 M_NSAFETYPOOLSIZE = 512;        // DEFAULT SIZE
}

來看這句:pThreadState->m_pCurrentWinThread = this;將this的值附給pThreadState指針的成員變量m_pCurrentWinThread,這裏的this指針到底指向的是哪一個對像呢?是我們的CTestApp對像還是CWinApp的都像呢?它指向的是派生類CTestApp的對象。也就是剛纔的theApp。

在看WinMain函數,實際上它是用了AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);函數來完成WinMain函數。Afx前綴是屬於應用程序框架類的函數,Application FrameWork x(x這裏沒有什麼意義).
依然是搜索這個函數AfxWinMain,找到winmain.cpp,打開看到:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 __in LPTSTR lpCmdLine, int nCmdShow)
{
 ...............
};
因爲C++不是完全面向對象的語言,所以要定義一些全局函數,來組織類之間的關係,這些全局函數我們叫做應用程序框架類的一些函數,以Afx打頭,在每一個類中都可以調用,因爲是全局的。
CWinApp* pApp = AfxGetApp();
這裏AfxGetApp();會獲得一個指向CWinApp的指針,實際上這裏獲得的指針,就是剛纔我們在CWinApp構造函數中附給的這個指針,也就是說這裏pApp指針指向的是派生類CTestApp的theApp指針。

步驟:
設計窗口類
註冊窗口類
創建窗口
顯示窗口
更新窗口
消息循環
消息處理函數

首先效用了InitApplication(),主要是MFC內部管理所調用的函數。
if (pApp != NULL && !pApp->InitApplication())
  goto InitFailure;
    
做個劃線的例子:
HDC hdc;   //生成一個HDC的對象
hdc=::GetDC(m_hWnd);  //這裏注意:this是c++的關鍵字,表示這個類的當前實例,m_hwnd是一個成員變量,好象是定義在CWnd裏面吧,他存放的是類的實例的句柄
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,Null); //將點移動到具體的位置,API
LindTo(hdc,point.x,point.y); //劃線,API
::ReleaseDC(m_hWnd,hdc); //釋放HDC

關於m_hWnd的疑惑:
this是c++的關鍵字,表示這個類的當前實例,m_hwnd是一個成員變量,好象是定義在CWnd裏面吧,他存放的是類的實例的句柄.、本窗口的句柄
m_hWnd 定義於 CWnd 類,其他類都是從它那裏派生來的。

很簡單常識,一些函數前的兩個冒號::是什麼意思,有什麼用?
作用域標識符.
使用外部命名空間的函數或變量.當外部與模塊內部函數或變量重名時,前面加::可以繼續使用外部的函數或變量,當然,它們必須是可見的。
表明該函數爲全局的而不是當前類的(噹噹前類中沒有該函數時,不加   ::   也是一樣的)

一般是系統API函數 
這是調用系統的api函數     
  呵呵~~   
  不像vb那樣還要聲明   
  呵呵~~   
系統API函數前使用::爲了和類擴展函數區別 
  直接就可以調:)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章