MFC源碼剖析之-MFC來龍去脈

上傳人:文*** 文檔編號(hào):62510976 上傳時(shí)間:2022-03-15 格式:DOC 頁(yè)數(shù):15 大?。?5.50KB
收藏 版權(quán)申訴 舉報(bào) 下載
MFC源碼剖析之-MFC來龍去脈_第1頁(yè)
第1頁(yè) / 共15頁(yè)
MFC源碼剖析之-MFC來龍去脈_第2頁(yè)
第2頁(yè) / 共15頁(yè)
MFC源碼剖析之-MFC來龍去脈_第3頁(yè)
第3頁(yè) / 共15頁(yè)

下載文檔到電腦,查找使用更方便

0 積分

下載資源

還剩頁(yè)未讀,繼續(xù)閱讀

資源描述:

《MFC源碼剖析之-MFC來龍去脈》由會(huì)員分享,可在線閱讀,更多相關(guān)《MFC源碼剖析之-MFC來龍去脈(15頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。

1、文檔供參考,可復(fù)制、編制,期待您的好評(píng)與關(guān)注! MFC源碼剖析之——MFC來龍去脈.txt熬夜,是因?yàn)闆]有勇氣結(jié)束這一天;賴床,是因?yàn)闆]有勇氣開始這一天。朋友,就是將你看透了還能喜歡你的人。MFC源碼剖析之——MFC來龍去脈 以傳統(tǒng)的C/SDK 撰寫Windows 程序,最大的好處是可以清楚看見整個(gè)程序的來龍去脈 和消息動(dòng)向,然而這些重要的動(dòng)線在MFC 應(yīng)用程序中卻隱晦不明,因?yàn)樗鼈儽籄pplication Framework 包起來了。這一章主要目的除了解釋MFC 應(yīng)用程序的長(zhǎng)像,也要從MFC 源代 碼中檢驗(yàn)出一個(gè)Windows 程序原本該有的程序進(jìn)入點(diǎn)(WinMain)、視窗

2、類別注冊(cè) (RegisterClass)、窗口產(chǎn)生(CreateWindow)、消息循環(huán)(Message Loop)、窗口函數(shù) (WindowProcedure)等等動(dòng)作,抽絲剝繭徹底了解一個(gè)MFC 程序的誕生與結(jié)束,以及生 命過程。 先來看個(gè)一般的C/SDK Windows程序: ////////////////////////////////////////////////////////////// // Generic.cpp 一般的windows程序流程演示 #include LRESULT CALLBACK MyWinProc(HWND,UI

3、NT,WPARAM,LPARAM);//○6 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { WNDCLASS wc; wc.cbClsExtra=0; wc.cbWndExtra=0; wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wc.hCursor=LoadCursor(NULL,IDC_ARROW); wc.hIcon=LoadIcon(NULL

4、,IDI_APPLICATION); wc.hInstance=hInstance; wc.lpfnWndProc=MyWinProc; wc.lpszClassName="generic"; wc.lpszMenuName=NULL; wc.style=CS_VREDRAW | CS_HREDRAW;//窗口的樣式 RegisterClass(&wc);//注冊(cè)窗口類○1 HWND hWnd; hWnd=CreateWindow( "generic", "Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,

5、 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);//產(chǎn)生窗口○2 ShowWindow(hWnd,SW_NORMAL);//顯示窗口○3 UpdateWindow(hWnd);//更新窗口○4 MSG msg; while(GetMessage(&msg,NULL,0,0)){ TranslateMessage(&msg); DispatchMessage(&msg); }//消息循環(huán)○5 return 0; } LRESULT

6、CALLBACK MyWinProc( HWND hwnd,//窗口句柄 UINT uMSG,//消息標(biāo)志符 WPARAM wParam,//消息的第一個(gè)參數(shù) LPARAM lParam//消息的第二個(gè)參數(shù) ) { switch(uMSG){ case WM_LBUTTONDOWN://鼠標(biāo)左鍵點(diǎn)擊 MessageBox(hwnd,"點(diǎn)擊","HelloWorld",MB_OK); break; case WM_CLOSE://窗口被關(guān)閉消息 if(IDYES==MessageBox(hwnd,"是否真的要關(guān)閉窗口?","提示",MB_YESNO)

7、){ DestroyWindow(hwnd); } break; case WM_PAINT://窗口被繪制時(shí)消息 HDC hDc; PAINTSTRUCT ps; hDc=BeginPaint(hwnd,&ps); TextOut(hDc,0,10,"第一行字符",10); EndPaint(hwnd,&ps); break; case WM_DESTROY://窗口被銷毀是消息 PostQuitMessage(0);//有了這個(gè)才可以使while(GetMessage(&MSG, , ,))為假 break;

8、 default://處理我不感興趣的消息 return DefWindowProc(hwnd,uMSG,wParam,lParam); } return 0; } 從上述的原碼中可以看出windows程序設(shè)計(jì)有個(gè)基本的脈絡(luò):Register Class(WNDCLASS*) →Create Window→Show Window→Update Window →Message Loop→Window procedure。但 我們從MFC中看不出有這么一個(gè)流程,甚至是看不到程序的入口function named WinMain。 即便是基于MFC的應(yīng)用程序,建立窗口類也

9、是會(huì)遵循如下的過程: 設(shè)計(jì)窗口類->注冊(cè)窗口類->生成窗口->顯示窗口->更新窗口->消息循環(huán)->消息路由到窗口 過程函數(shù)處理。下面就剖析一下在MFC中是如何完成上述過程的。 (1)每個(gè)應(yīng)用程序都有且僅有一個(gè)應(yīng)用類的全局變量theApp,全局變量先于WinMain函數(shù)進(jìn) 行處理。 (2)WinMain函數(shù)體在APPMODUL.CPP文件中,定義如下: extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { /

10、/ call shared/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } 其中#define _tWinMain WinMain (3)AfxWinMain函數(shù)體在WINMAIN.CPP文件中,里面有如下兩句話: CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp(); 其實(shí)這里得到的這兩個(gè)指針都是指向全局的對(duì)象theApp的; 接下來有函數(shù)調(diào)用pThread->InitInsta

11、nce(),根據(jù)多態(tài)性,會(huì)調(diào)用CXXXApp類中的 InitInstance()函數(shù)。該 函數(shù)很重要,在對(duì)該函數(shù)的調(diào)用中就會(huì)完成:設(shè)計(jì)窗口類->注冊(cè) 窗口類->生成窗口->顯示窗口->更新窗口。 接下來,該函數(shù)中會(huì)繼續(xù)調(diào)用pThread->Run(),這就完成了:消息循環(huán)->消息路由到窗口過 程函數(shù)處理。 (4)進(jìn)入CXXXApp::InitInstance()函數(shù)體中,對(duì)于單文檔應(yīng)用程序,調(diào)用 ProcessShellCommand(cmdInfo),通過調(diào)用該函數(shù)就會(huì)完成:設(shè)計(jì)窗口類->注冊(cè)窗口類-> 生成窗口。 再接下來就會(huì)調(diào)用m_pMainWnd->ShowWindow

12、(SW_SHOW);m_pMainWnd->UpdateWindow();這就 完成了:顯示窗口->更新窗口。 (5)在函數(shù)CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)中會(huì)進(jìn)入到如 下的case分支:case CCommandLineInfo::FileNew: if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)) (6)進(jìn)入函數(shù)CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHA

13、NDLERINFO* pHandlerInfo),調(diào)用_AfxDispatchCmdMsg(this, nID, nCode, lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo); (7)進(jìn)入函數(shù)AFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode, AFX_PMSG pfn, void* pExtra, UINT nSig, AFX_CMDHANDLERINFO* pHandlerInfo),調(diào)用 case AfxSig_vv: // normal co

14、mmand or control notification ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED ASSERT(pExtra == NULL); (pTarget->*mmf.pfn_COMMAND)(); (8)進(jìn)入CWinApp::OnFileNew(),調(diào)用m_pDocManager->OnFileNew();這個(gè)函數(shù)很特殊,它 本身是個(gè)消 息響應(yīng)函數(shù),當(dāng)我們點(diǎn)擊ID為ID_FILE_NEW的菜單時(shí),會(huì)產(chǎn)生一個(gè)命令消息,由 于命令消息可以被CCmdTarget類及其派生類來捕獲,而 CWinApp是

15、從CCmdTarget派生出來的, 因此可以捕獲這個(gè)消息。當(dāng)應(yīng)用程序創(chuàng)建完成并成功顯示后,當(dāng)我們點(diǎn)擊文件菜單下的新建 菜單項(xiàng)時(shí),就會(huì) 首先進(jìn)入這個(gè)函數(shù),然后再依次執(zhí)行下去,最后就會(huì)執(zhí)行到 pDocument->OnNewDocument()中,往往我們會(huì)對(duì)這個(gè)函數(shù)不解,不知 道它為什么會(huì)響應(yīng) ID_FILE_NEW的命令消息,至此真相大白了。順便說一句,為什么程序在剛啟動(dòng)的時(shí)候,我 們并沒有點(diǎn)擊菜單項(xiàng),為什么會(huì)自動(dòng)的產(chǎn)生 這個(gè)消息呢?這是因?yàn)樵? CXXXXApp::InitInstance()函數(shù)中有“CCommandLineInfo cmdInfo;”這個(gè)類的構(gòu)造函數(shù)是這 樣的

16、:CCommandLineInfo::CCommandLineInfo() { m_bShowSplash = TRUE; m_bRunEmbedded = FALSE; m_bRunAutomated = FALSE; m_nShellCommand = FileNew; },因此就會(huì)在第(5)步驟的時(shí)候進(jìn)入到“case CCommandLineInfo::FileNew:”這個(gè)分支中, 就相當(dāng)于產(chǎn)生了這樣一個(gè)FileNew的消息。同理對(duì)于ID為 ID_FILE_OPEN(在 CWinApp::OnFileOpen()中響應(yīng))、ID_FILE_SAVE(在 CDocument

17、::OnFileSave()中響應(yīng)) 等等在MFC向?qū)槲覀兩傻膯挝臋n類中找不到消息響應(yīng)的入口時(shí),其實(shí)都是在基類CWinApp 或者CDocument類中進(jìn)行了響應(yīng)。對(duì)于CXXXXDoc::Serialize(CArchive& ar)函數(shù)也是通過 ID_FILE_SAVE和ID_FILE_OPEN產(chǎn)生命令消息后就行響應(yīng)從而才調(diào)用該函數(shù)的。 (9)進(jìn)入CDocManager::OnFileNew(),CDocManager類有一個(gè)成員變量是CPtrList m_templateList;該變量保存了一個(gè)文檔模版鏈表指針,在CDocManager::OnFileNew()函數(shù) 體中

18、會(huì)調(diào)用 CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();得 到鏈表中的頭,也就是第一個(gè)文檔模版,后面就會(huì)用得到的這個(gè)指針去 調(diào)用 pTemplate->OpenDocumentFile(NULL);緊接著就會(huì)有一個(gè)判斷,用來確定該鏈表中是否只有 一項(xiàng),如果鏈表中保存 了多個(gè)文檔模版,則會(huì)彈出一個(gè)對(duì)話框,來讓我們選擇到底是使用 哪一套文檔模版來構(gòu)建應(yīng)用程序,相信大家也都見到過這種情況吧。對(duì)了,還有一點(diǎn)要說明 的 是:pTemplate是一個(gè)CDocTemplate的指針,但接下來程序?yàn)槭裁磿?huì)進(jìn)入到

19、 CSingleDocTemplate::OpenDocumentFile的函數(shù)體內(nèi)呢,這是因?yàn)镃DocTemplate類中的 OpenDocumentFile函數(shù)被定義為純虛函數(shù),而CSingleDocTemplate類又是從CDocTemplate 類派生出來的,并且實(shí) 現(xiàn)了該函數(shù),因此就會(huì)進(jìn)入到子類的函數(shù)體中了。 (10)進(jìn)入CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible),先調(diào)用CreateNewDocument()創(chuàng)建文檔類,再調(diào)用pFrame =

20、 CreateNewFrame(pDocument, NULL);創(chuàng)建框架類和視圖類,從這里也可以看出MFC體系結(jié)構(gòu) 中文檔、框架、視圖“三位一體”的模式,在這一個(gè)函數(shù)中同時(shí)創(chuàng)建三個(gè)類;再會(huì)調(diào)用 pDocument->OnNewDocument();因此就會(huì)進(jìn)入到子類的文檔類中的 pDocument->OnNewDocument()中了。 (11)進(jìn)入CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther),調(diào)用if (!pFrame->LoadFrame(m_nIDResource, W

21、S_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, // default frame styles NULL, &context)) (12)進(jìn)入BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext),調(diào)用 VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); (13)進(jìn)入BOOL AFXAPI AfxEndDeferRegisterClass(

22、LONG fToRegister),該函數(shù)內(nèi)部就完 成了:設(shè)計(jì)窗口類->注冊(cè)窗口類。MFC通過給我們提供好一些已經(jīng)訂制好的窗口類,我們不 需要自己再設(shè)計(jì) 窗口類,只需要到那些訂制好的窗口類“倉(cāng)庫(kù)”中尋找一種適合我們需要的 窗口類就可以了,然后通過AfxRegisterClass函數(shù)注冊(cè)窗口類。還需要 說明的是,再后續(xù) 的跟蹤過程中,我們會(huì)發(fā)現(xiàn)還會(huì)進(jìn)入到AfxEndDeferRegisterClass函數(shù)中進(jìn)行設(shè)計(jì)和注冊(cè)窗 口類,這主要是因?yàn)閱挝臋n 應(yīng)用程序比較特殊,它提前通過這樣的一種途徑進(jìn)行了窗口類 的設(shè)計(jì)和注冊(cè)步驟,其實(shí)是應(yīng)該在BOOL CMainFrame::PreCreat

23、eWindow(CREATESTRUCT& cs) 函數(shù)的調(diào)用中完成窗口類的設(shè)計(jì)和注冊(cè)的,這一點(diǎn)我們要清楚,也就是說設(shè)計(jì)和注冊(cè)窗口類 的正宗發(fā)源地應(yīng)該是 PreCreateWindow(CREATESTRUCT& cs)。此外,我們還會(huì)注意到在該函 數(shù)體的前部分有一語(yǔ)句為“wndcls.lpfnWndProc = DefWindowProc;”因此所有窗口類的窗口 過程函數(shù)都是DefWindowProc,這一點(diǎn)在后面的跟蹤中可以看到,每次生成窗口之后都會(huì)調(diào) 用 幾次DefWindowProc函數(shù)。也就是說MFC都是讓我們采用默認(rèn)的窗口過程函數(shù),這并不是 說我們因此就不能使用自己的窗

24、口過程函數(shù)實(shí)現(xiàn)個(gè)性化的消 息處理了,MFC采用了一種基于 消息映射的機(jī)制完成了消息個(gè)性化處理。 (14)回到BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)中,調(diào)用LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); (15)進(jìn)入LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle,

25、 UINT nIDResource),調(diào)用PreCreateWindow(cs); (16)進(jìn)入BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs),調(diào)用 CFrameWnd::PreCreateWindow(cs) (17)進(jìn)入BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs),調(diào)用 VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));又一次設(shè)計(jì)和注冊(cè)窗口類 (18)回到BOOL CFrameWnd::LoadFrame(UINT

26、 nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)中,調(diào)用if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext)) (19)進(jìn)入BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle,

27、 const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext),調(diào)用if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) (

28、20)BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam),調(diào)用if (!PreCreateWindow(cs)) ,接下來調(diào)用HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName,

29、 cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);好了,終于讓我們找到 生成窗口的地方了——函數(shù)::CreateWindowEx! (21)進(jìn)入int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct),調(diào)用if (CFrameWnd::OnCreate(lpCreateStruct) == -1) (22)進(jìn)入int CFrameWnd::OnCreate(LPCREATESTRUCT lpc

30、s),調(diào)用return OnCreateHelper(lpcs, pContext); (23)進(jìn)入int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext),調(diào)用if (CWnd::OnCreate(lpcs) == -1) (24)進(jìn)入_AFXWIN_INLINE int CWnd::OnCreate(LPCREATESTRUCT),調(diào)用return (int)Default(); (25)進(jìn)入LRESULT CWnd::Default(),調(diào)用return DefWindowPro

31、c(pThreadState->m_lastSentMsg.message, pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam); (26)進(jìn)入LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam), 調(diào)用return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam); (27)回到int CFrameWnd::OnCreateHelper(LPC

32、REATESTRUCT lpcs, CCreateContext* pContext),調(diào)用if (!OnCreateClient(lpcs, pContext)) (28)進(jìn)入BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext),調(diào)用if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) (29)進(jìn)入CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID),調(diào)用 if (

33、!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext)) (30)進(jìn)入BOOL CWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext),調(diào)用return CreateEx(0, lpszClassName, lpszWindowName

34、, dwStyle | WS_CHILD, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext); (31)進(jìn)入BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight,

35、 HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam),重復(fù)生成框架類CMainFrame的 過程來生成CXXXView,因?yàn)樗彩且粋€(gè)窗口類,因此也需要進(jìn)行那一系列過程才能最終顯示 更新出來。 調(diào)用的順序是這個(gè)樣子的:PreCreateWindow(cs)->BOOL CXXXView::PreCreateWindow(CREATESTRUCT& cs)->CView::PreCreateWindow(cs)->VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIE W_REG));->::Cr

36、eateWindowEx(...)->CWnd::DefWindowProc->::CallWindowProc(...)->.. .->CXXXView::OnCreate->CView::OnCreate->CWnd::OnCreate->... 寫到這里,基本上就清楚了,中間的省略號(hào)表示的部分大多數(shù)都是在與窗口過程函數(shù)有關(guān)的, 因?yàn)樵谏纱翱诘臅r(shí)候需要響應(yīng)一些消息,因此需要調(diào)用一些窗口過程 函數(shù),每次在調(diào) 用::CreateWindowEx(...)函數(shù)后都會(huì)調(diào)用一些窗口過程函數(shù),然后再去調(diào)用該窗口類對(duì)應(yīng) 的OnCreate函數(shù),其實(shí)在 調(diào)用OnCreate函數(shù)之前調(diào)用Crea

37、teWindowEx只是生成了一個(gè)窗口, 至于這個(gè)窗口里面要放置些什么東西,以及該如何裝飾該窗口,則就需要 由OnCreate來完 成了,往往我們都會(huì)在OnCreate函數(shù)的后面(這樣做是為了不影響窗口本身應(yīng)該布置的格局) 添加一些代碼,創(chuàng)建我們自己的東 西,比如我們通常會(huì)在CMainFrame類的OnCreate函數(shù)后 面放置一些Create代碼,來創(chuàng)建我們自己的可??康墓ぞ邫诨蛘甙粹o之類的東西, 當(dāng)然我 們也可以在CXXXView類的OnCreate函數(shù)的后面添加一些代碼,來創(chuàng)建我們需要的東西,比如 按鈕之類的東西。在完成了從設(shè)計(jì)、注冊(cè)到生成 窗口的過程之后,往往還需要顯示更新

38、, 有些時(shí)候,我們不必要每次都顯示的調(diào)用CWnd的ShowWindow和UpdateWindow兩個(gè)函數(shù),我們 可 以在創(chuàng)建的時(shí)候,給窗口風(fēng)格中添加WS_VISIBLE即可,因此有些時(shí)候會(huì)跟蹤不到 ShowWindow和UpdateWindow兩個(gè)函數(shù)這兩個(gè)函 數(shù),因?yàn)榇翱谠趧?chuàng)建的時(shí)候就可見了。 總的來說,先初始化應(yīng)用類,然后注冊(cè)生成框架類,然后再注冊(cè)生成視圖類,然后注冊(cè) 生成視圖類OnCreate函數(shù)后面用戶添加的、用Create來準(zhǔn)備創(chuàng) 建的窗口,然后再注冊(cè)生成 框架類的OnCreate函數(shù)后面需要生成的m_wndToolBar、m_wndStatusBar以及我們自己添加的

39、 要?jiǎng)?chuàng)建 的窗口類,最后在回到應(yīng)用類的初始化的函數(shù)體中,調(diào)用框架類的顯示和更新函數(shù), 然后再進(jìn)入由框架類定義的窗口的消息循環(huán)中。 消息循環(huán)的過程是這個(gè)樣子的: (1)調(diào)用int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)函數(shù)中的pThread->Run() (2)進(jìn)入int CWinApp::Run(),調(diào)用return CWinThread::Run(); (3)進(jìn)入int CWinThread::Run(),調(diào)用if (!PumpM

40、essage()) (4)進(jìn)入BOOL CWinThread::PumpMessage(),調(diào)用if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) (5)回到BOOL CWinThread::PumpMessage(),調(diào) 用::TranslateMessage(&m_msgCur);::DispatchMessage(&m_msgCur); (6)回到int CWinThread::Run(),調(diào)用while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); (7)再

41、重復(fù)(4)-(6)的步驟 下面給出int CWinThread::Run()中消息循環(huán)的部分代碼: do { // pump message, but quit on WM_QUIT if (!PumpMessage()) return ExitInstance(); // reset "no idle" state after pumping "normal" message if (IsIdleMessage(&m_msgCur)) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(&m_msgC

42、ur, NULL, NULL, NULL, PM_NOREMOVE)); 這段代碼其實(shí)本質(zhì)上與我們基于Win32 SDK手寫的代碼: //消息循環(huán) MSG msg; while(GetMessage(&msg,NULL,0,0)) { //簡(jiǎn)單的說,函數(shù)TranslateMessage就是把WM_KEYDOWN和WM_KEYUP翻譯成WM_CHAR消息,沒 有該函數(shù)就不能產(chǎn)生WM_CHAR消息。 TranslateMessage(&msg); ::DispatchMessage(&msg); } 是一致的。 Visual C++ MFC 中常用宏的含義 AND_CAT

43、CHAND_CATCH AND_CATCH(exception_class,exception _object_point_name) 說明: 定 義一個(gè)代碼塊,它用于獲取廢除當(dāng)前TRY塊中的附加異常類型。使用CATCH宏以獲得一個(gè) 異常類型,然后使用AND_CATCH宏獲得隨后的異常處理代碼 可以訪問異常對(duì)象(若合適的 話)已得到關(guān)于異常的特別原因的更多消息。在AND_CATCH塊中調(diào)用THROW_LAST宏以便把處 理過程移到下個(gè)外部異 常框架。AND_CATCH可標(biāo)記CATCH或AND_CATCH塊的末尾。 注釋: AND_CATCH塊被定義成為一個(gè)C++作用域(由花括號(hào)

44、來描述)。若用戶在此作用域定義變量, 那么記住他們只在此作用域中可以訪問。他也用于exception_object_pointer_name變量。 ASSERT ASSERT(booleanExpression) 說明: 計(jì) 算變量的值。如果結(jié)構(gòu)的值為0,那么此宏便打印一個(gè)診斷消息并且成訊運(yùn)行失敗。如果 條件為非0,那么什么也不做。 診斷消息的形式為: assertion failed in file in line 其中name 是元文件名,num是源文件中運(yùn)行失敗的中斷號(hào)。 在Release版中,ASSERT不計(jì)算表達(dá)式的 值也就不中斷程序。如果必須計(jì)算此表達(dá)式的值且不管環(huán)

45、境如何那么用VERIFY代替ASSERT。 注釋: ASSERT只能在Debug版中用 ASSERT_VAILD ASSERT_VAILD(pObject) 說明: 用 于檢測(cè)關(guān)于對(duì)象的內(nèi)部狀態(tài)的有效性。ASSERT_VALID調(diào)用此對(duì)象的AssertValid成員函數(shù) (把它們作為自己的變量來傳遞)。在 Release版中ASSERT_VALID什么也不做。在DEBUG版中, 他檢查指針,以不同于NULL的方式進(jìn)行檢查,并調(diào)用對(duì)象自己的 AssertValid成員函數(shù)。如 果這些檢測(cè)中有任何一個(gè)失敗的話,那么他會(huì)以與ASSERT相同的方法顯示一個(gè)警告的消息。 注釋: 此

46、函數(shù)只在DEBUG版中有效。 BEGIN_MESSAGE_MAP BEGIN_MESSAGE_MAP(the class,baseclass) 說明: 使用BEGIN_MESSAGE_MAP開始用戶消息映射的定義。在定義用戶類函數(shù)的工具(.cpp)文 件中,以BEGIN_MESSAGE_MAP宏開始消息映射,然后為每個(gè)消息處理函數(shù)增加宏項(xiàng),接著 以END_MESSAGE_MAP宏完成消息映射。 CATCH CATCH(exception_class,exception_object_pointer_name) 說明: 使 用此用定義一個(gè)代碼塊,此代碼用來獲取當(dāng)前TRY塊中都

47、一個(gè)異常類型。異常處理代碼可 以訪問異常對(duì)象,如何合適的話,就會(huì)得到關(guān)于異常的特殊原因的更多消 息。調(diào)用 THROW_LAST宏以把處理過程一下一個(gè)外部異??蚣埽绻鹐xception‐class是類CExceptioon, 那么會(huì)獲取所有異常 類型。用戶可以使用CObject::IsKindOf成員函數(shù)以確定那個(gè)特別異常被 排除。一種獲取異常的最好方式是使用順序的AND_CATCH語(yǔ)句, 每個(gè)帶一個(gè)不同的異常類 型。此異常類型的指針由宏定義,用戶不必定義。 注釋: 此CATCH塊被定義作一個(gè)C++范圍(由花括號(hào)描述)。如用戶在此范圍定義變量,那么它們只 在吃范圍內(nèi)可以訪問。他

48、還可以用于異常對(duì)象的指針名。 DEBUG_NEW #define new DEBUG_NEW 說明: 幫 助查找內(nèi)存錯(cuò)誤。用戶在程序中使用DEBUG_NEW,用戶通常使用new運(yùn)算符來從堆上分配。 在Debug模式下(但定義了一個(gè)DEBUG符 號(hào)),DEBUG_NEW為它分配的每個(gè)對(duì)象記錄文件名 和行號(hào)。然后,在用戶使用CMemoryState::DumpAllObjectSince成員 函數(shù)時(shí),每個(gè)以 DEBUG_NEW分配的對(duì)象分配的地方顯示出文件名和行號(hào)。 為了使用DEBUG_NEW,應(yīng)在用戶 的資源文件中插入以下指令: #define new DEBUG_NEW 一旦用

49、戶插入本指令,預(yù)處理程序 將在使用new的地方插入DEBUG_NEW,而MFC作其余的工作。但用戶編譯自己的程序的一個(gè) 發(fā)行版 時(shí),DEBUG_NEW便進(jìn)行簡(jiǎn)單的new操作,而且不產(chǎn)生文件名和行號(hào)消息。 DECLARE_DYNAMIC DECLARE_DYNAMIC(class_name) 說明: 但 從CObject派生一個(gè)類時(shí),此宏增加關(guān)于一個(gè)對(duì)象類的訪問運(yùn)行時(shí)間功能。把 DECLARE_DYNAMIC宏加入類的頭文件中,然后在全部需要訪問詞 類對(duì)象的.CPP文件中都包 含此模塊。如果像所描述那樣使用DELCARE_DYNAMIC和IMPLEMENT_DYNAMIC宏,那么

50、用戶 便可使用 RUNTIME_CLASS宏和CObject::IsKindOf函數(shù)以在運(yùn)行時(shí)間決定對(duì)象類。如果 DECLARE_DYNAMIC包含在類定義中,那 么IMPLEMETN_DYNAMIC必須包含在類工具中。 DECLARE_DYNCREATE DECLARE_DYNCREATE(class_name) 說明: 使 用DECLARE_DYNCRETE宏以便允許CObject派生類的對(duì)象在運(yùn)行時(shí)刻自動(dòng)建立。主機(jī)使用 此功能自動(dòng)建立新對(duì)象,例如,但它在串行化過程中 從磁盤讀一個(gè)對(duì)象時(shí),文件及視圖和 框架窗應(yīng)該支持動(dòng)態(tài)建立,因?yàn)榭蚣苄枰詣?dòng)建立它。把DECLARE_DYN

51、CREATE宏加入類的.H 文件中,然后在 全部需要訪問此類對(duì)象的.CPP文件中包含這一模式。如果 DECLARE_DYNCREATE包含在類定義中,那么 IMPLEMENT_DYNCREATE必須包含在類工具中。 DECLARE_MESSAGE_MAP DECLARE_MESSAGE_MAP() 說明: 用 戶程序中的每個(gè)CCmdTarget派生類必須提供消息映射以處理消息。在類定義的末尾使用 DECLARE_MESSAGE_MAP宏。接著,在定義類成 員函數(shù)的.CPP文件中,使用 BEGIN_MESSAGE_MAP宏,每個(gè)用戶消息處理函數(shù)的宏項(xiàng)下面的列表以及 END_ME

52、SSAGE_MAP宏。 注釋: 如果在DECLARE_MESSAGE_MAP之后定義任何一個(gè)成員,那么必須為他們指定一個(gè)新存取類 型(公共的,私有的,保護(hù)的)。 DECLARE_SERIAL DECLARE_SERIAL(class_name) 說明: DECLARE_SERIAL 為一個(gè)可以串行化的CObject派生類產(chǎn)生必要的C++標(biāo)題代碼。串行化是把 某個(gè)對(duì)象的內(nèi)容從一個(gè)文件讀出和寫入一文件。在.H文件中使用 DECLARE_SERIAL宏,接著 在需要訪問此類對(duì)象的全部.CPP文件中包含此文件。如果DECLARE_SERIAL包含在類定義中, 那么 IMPLEMEN

53、T_SERIAL必須包含在類工具中。DECLARE_SERIAL宏包含全部 DECLARE_DYNAMIC,IMPLEMENT_DYCREATE的功能。 END_CATCH END_CATCH 說明: 標(biāo)識(shí)最后的CATCH或AND_CATCH塊的末尾。 END_MESSAGE_MAP END_MESSAGE_MAP 說明: 使用END_MESSAGE_MAP宏結(jié)束用戶的消息映射定義 IMPLEMENT_DYNAMIC IMPLEMENT_DYNAMIC(class_name,base_class_name) 說明: 通過運(yùn)行時(shí)在串行結(jié)構(gòu)中為動(dòng)態(tài)CObject派生類訪問

54、類名和位置來產(chǎn)生必要的C++代碼。 在.CPP文件中使用IMPLEMENT_DYNAMIC宏,接著一次鏈接結(jié)果對(duì)象代碼 IMPLEMENT_DYNCREATE IMPLEMENT_DYNCREATE(class_name,base_class_name) 說明: 通 過DECLARE_DYNCREATE宏來使用IMPLEMENT_DYNCREATE宏,以允許CObject派生類對(duì)象在 運(yùn)行時(shí)自動(dòng)建立。主機(jī)使用此 功能自動(dòng)建立對(duì)象,例如,但它在串行化過程中從磁盤讀去 一個(gè)對(duì)象時(shí),他在類工具里加入IMPLEMENT_DYNCREATE宏。若用戶使用 DECLARE_DYNCREAT

55、E和IMPLEMENT_DYNCREATE宏,那么接著使用RUNTIME_CLASS宏和 CObject::IsKindOf成員函數(shù)以在運(yùn)行時(shí)確定對(duì)象類。若declare_dyncreate包含在定義中,那么 IMPLEMENT_DYNCREATE必須包含在類工具中。 IMPLEMENT_SERIAL IMPLEMENT_SERIAL(class_name,base_class_name,wSchema) 說明: 通過運(yùn)行時(shí)在串行結(jié)構(gòu)中動(dòng)態(tài)CObject派生類訪問類名和位置來建立必要的C++代碼。在.CPP 文件中使用IMPLEMENT_SERIAL宏,然后一次鏈接結(jié)果對(duì)象代碼。

56、 ON_COMMAND ON_COMMAND(id,memberFxn) 說明: 此 宏通過ClassWizard或手工插入一個(gè)消息映射。它表明那個(gè)函數(shù)將從一個(gè)命令用戶接口(例 如一個(gè)菜單項(xiàng)或toolbar按鈕)處理一個(gè)命令消息。當(dāng) 一個(gè)命令對(duì)象通過指定的ID接受到一 個(gè)Windows WM_COMMAND消息時(shí),ON_COMMAND將調(diào)用成員函數(shù)memberFxn處理此消息。 在用戶的消息映射中,對(duì)于每個(gè)菜單或加速器命令(必須被 映射到一個(gè)消息處理函數(shù))應(yīng) 該確實(shí)有一個(gè)ON_COMMAND宏語(yǔ)句。 ON_CONTROL ON_CONTROL(wNotifyCode,id,

57、memberFxn) 說明: 表明哪個(gè)函數(shù)將處理一個(gè)常規(guī)控制表示消息。控制標(biāo)識(shí)消息是那些從一個(gè)控制夫發(fā)送到母窗 口的消息。 ON_MESSAGE ON_MESSAGE(message,memberFxn) 說明: 指 明哪個(gè)函數(shù)將處理一用戶定義消息。用戶定義消息通常定義在WM_USER到0x7FF范圍內(nèi)。 用戶定義消息是那些不是標(biāo)準(zhǔn)Windows WM_MESSAGE消息的任何消息。在用戶的消息映射 中,每個(gè)必須被映射到一個(gè)消息處理函數(shù)。用戶定義消息應(yīng)該有一個(gè)ON_MESSAGE宏語(yǔ)句。 ON_REGISTERED_MESSAGE ON_REGISTERED_MESSAG

58、E(nmessageVarible,memberFxn) 說明: Windows的RegisterWindowsMesage函數(shù)用于定義一個(gè)新窗口消息,此消息保證在整個(gè)系統(tǒng)中 是唯一的。此宏表明哪個(gè)函數(shù)處理已注冊(cè)消息。變量nMessageViable應(yīng)以NEAR修飾符來定義。 ON_UPDATE_COMMAND_UI ON_UPDATE_COMMAND_UI(id,memberFxn) 說明: 此宏通常通過ClassWizard被插入一個(gè)消息映射,以指明哪個(gè)函數(shù)將處理一個(gè)用戶接口個(gè)更改 命令消息。在用戶的消息映射中,每個(gè)用戶接口更改命令(比訊被映射到一個(gè)消息處理函數(shù)) 應(yīng)該有

59、一個(gè)ON_UPDATE_COMMAND_UI宏語(yǔ)句。 ON_VBXEVENT ON_VBXEVENT(wNotifyCode,memberFxn) 說明: 此宏通常通過ClassWizard被插入一個(gè)消息映射,以指明哪個(gè)函數(shù)將處理一個(gè)來自VBX控制的 消息。在用戶的消息映射中每個(gè)被映射到一消息處理函數(shù)的VBX控制消息應(yīng)該有一個(gè)宏語(yǔ)句。 RUNTIME_CLASS RUNTIME_CLASS(class_name) 說明: 使 用此宏從c++類民眾獲取運(yùn)行時(shí)類結(jié)構(gòu)。RUNTIME_CLASS為由class_name指定的類返回一 個(gè)指針到CRuntimeClass結(jié)構(gòu)。只 有

60、以DECLARE_DYNAMIC,DECLARE_DYNCREATE或 DECLARE_SERIAL定義的CObject派生類才返回到一個(gè) CRuntimeClass結(jié)構(gòu)的指針。 THROW THROW(exception_object_pointer) 說明: 派出指定的異常。THROW中斷程序的運(yùn)行,把控制傳遞給用戶程序中的相關(guān)的CATCH塊。如 果用戶沒有提供CATCH塊,那么控制被傳遞到一個(gè)MFC模塊,他打印出一個(gè)錯(cuò)誤并終止運(yùn)行。 THROW_LAST THROW_LAST() 說明: 此宏允許用戶派出一個(gè)局部建立的異常。如果用戶試圖排除一個(gè)剛發(fā)現(xiàn)的異常,那么一般此

61、 異常將溢出并被刪除。使用THROW_LAST,此異常被直接傳送到下一個(gè)CATCH處理程序。 TRACE TRACE(exp) 說明: 把 一個(gè)格式化字符串送到轉(zhuǎn)儲(chǔ)設(shè)備,例如,文件或調(diào)試監(jiān)視器,而提供與printf相似的功能。 同MS_DOS下C程序的printf一樣,TRACE宏是一 個(gè)在程序運(yùn)行時(shí)跟蹤變量值的方便形式。在 DEBUG環(huán)境中,TRACE宏輸出到afxDump。在Release版中他不做任何工作。 注釋: 此宏只在MFC的DEBUG版中有效。 TRACE0 TRACE0(exp) 說明: 與 TRACE相似,但他把跟蹤字符串放在代碼段中,而不是DGRO

62、UP,因此使用少的DGROUP空 間。TRACE0是一組跟蹤宏的一個(gè)變體,這些宏可用于 調(diào)試輸出。這一組包括 TRACE0,TRACE1,TRACE2和TRACE3,這些宏不同在于所取參數(shù)的數(shù)目不同。TRACE0只取一個(gè)格 式化字符串并 可用于簡(jiǎn)單文本消息。TRACE1取一格式化字符串加上一個(gè)變量——一個(gè)將轉(zhuǎn) 儲(chǔ)的變量。同樣,TRACE2,TRACE3分別取2個(gè)或3個(gè)參數(shù)(在格式化 字符串之后)。如果用戶 以便以了應(yīng)用程序的發(fā)行版,那么它只把數(shù)據(jù)轉(zhuǎn)儲(chǔ)到afxDump。 注釋: 此宏只在MFC的DEBUG中有效。 TRACE1 TRACE1(exp,param1) 說明:

63、參見TRACE0 TRACE2 TRACE2(exp,param1,param2) 說明: 參見TRACE0 TRACE3 TRACE3(exp,param1,param2,param3) 說明: TRY TRY 說明: 使用此宏建立一TRY塊。一個(gè)TRY識(shí)別一個(gè)可排除異常的代碼塊。這些異常在隨后的CATCH和 AND_CATCH塊處理。傳遞是允許的:異常可以傳遞一個(gè)外部TRY塊,或者忽略它們或者使用 THROW_LAST宏。 VERIFY VERIFY(booleanExpression) 說明: 在 MFC的DEBUG版中,VERIFY宏計(jì)算它的變量值。 如果結(jié)果為0,那么宏打印一個(gè)診斷消 息并中止程序。如果條件不為0,那么什么工作也不作。 診斷有如下形式: assertion failed in file in line 其中name是源文件的名字,num是在源文件中失敗的中止行號(hào)。在MFC的Release 版中,VERIFY計(jì)算表達(dá)式值但不打印或中止程序。例如:如 果表達(dá)式是個(gè)函數(shù)調(diào)用,那么 調(diào)用成功 15 / 15

展開閱讀全文
溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

相關(guān)資源

更多
正為您匹配相似的精品文檔

相關(guān)搜索

關(guān)于我們 - 網(wǎng)站聲明 - 網(wǎng)站地圖 - 資源地圖 - 友情鏈接 - 網(wǎng)站客服 - 聯(lián)系我們

copyright@ 2023-2025  zhuangpeitu.com 裝配圖網(wǎng)版權(quán)所有   聯(lián)系電話:18123376007

備案號(hào):ICP2024067431號(hào)-1 川公網(wǎng)安備51140202000466號(hào)


本站為文檔C2C交易模式,即用戶上傳的文檔直接被用戶下載,本站只是中間服務(wù)平臺(tái),本站所有文檔下載所得的收益歸上傳人(含作者)所有。裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)上載內(nèi)容本身不做任何修改或編輯。若文檔所含內(nèi)容侵犯了您的版權(quán)或隱私,請(qǐng)立即通知裝配圖網(wǎng),我們立即給予刪除!