LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){ // TODO: Place code here. MSG msg; ……………………………… MyRegisterClass(hInstance); if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam;}BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){ …………………… return TRUE;}//窗口函数WndProc(),回调函数LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ int wmId, wmEvent; …………………… switch (message) { case WM_COMMAND: ……………… break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... RECT rt; GetClientRect(hWnd, &rt); DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); EndPaint(hWnd, &ps); break; case WM_DESTROY: …… default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0;} |
二、 MFC应用结构 在前面我分析了一个经典的SDK应用程序的结构,现在可是要进入主题“MFC应用程序结构”了。MFC应用程序有好多种,为了能够更清楚地与前面的文章形成对比,我们在这里看一个SDI的应用程序,当然例子还是经典的“Hello World”了。在使用向导生成应用程序后,会发现有好几个文件,首先我们不管有哪些文件,按照程序执行得主线抽取主要的源程序分析一下再说(因为MFC生成的应用程序不是很方便阅读,所以在这里我将他们重新编辑了)。
CHelloWorldApp theApp;int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow){ CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp(); // AFX internal initialization if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) goto InitFailure; // App global initializations (rare) if (pApp != NULL && !pApp->InitApplication()) goto InitFailure; // Perform specific initializations if (!pThread->InitInstance()) { if (pThread->m_pMainWnd != NULL) { TRACE0("Warning: Destroying non-NULL m_pMainWnd\n"); pThread->m_pMainWnd->DestroyWindow(); } nReturnCode = pThread->ExitInstance(); goto InitFailure; } nReturnCode = pThread->Run(); InitFailure: …………………… AfxWinTerm(); return nReturnCode;}BOOL CWinApp::InitApplication(){ if (CDocManager::pStaticDocManager != NULL) { if (m_pDocManager == NULL) m_pDocManager = CDocManager::pStaticDocManager; CDocManager::pStaticDocManager = NULL; } if (m_pDocManager != NULL) m_pDocManager->AddDocTemplate(NULL); else CDocManager::bStaticInit = FALSE; return TRUE;}BOOL CHelloWorldApp::InitInstance(){ AfxEnableControlContainer(); ……………………………… // Change the registry key under which our settings are stored. // TODO: You should modify this string to be something appropriate // such as the name of your company or organization. SetRegistryKey(_T("Local AppWizard-Generated Applications")); LoadStdProfileSettings(); // Load standard INI file options (including MRU) // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CHelloWorldDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CHelloWorldView)); AddDocTemplate(pDocTemplate); // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; // The one and only window has been initialized, so show and update it. m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE;}BOOL CWinApp::InitInstance(){ return TRUE;} |
三、MFC结构剖析 在前面我分别给出了SDK和MFC应用程序的框架,并且稍微理了一下它们之间的对应关系。但是对于MFC程序来说,要想真正搞懂它的框架的话,还是不够的。现在我要做的事就是继续去分析一下上面的MFC程序,期望能够如我的标题所言,明明白白的看透MFC的应用程序框架。
首先就是看一下应用向导生成的MFC应用程序都有哪些主要的文件,包含哪些类以及相关类的对应功能和他们之间的关系(再次说明,因为我在这里关心的是程序的框架结构,所以对于一些与话题关系不很大的东西我将会略去不提)。 在上面的SDI应用程序中,向导为我们生成了4个主要的类,这些类都是MFC类的派生类,分别包含在对应的头文件以及实现文件中。 1、 框架窗口类及其相关的文件 框架窗口类对应应用程序的主窗口,明白这一点后就可以建立一个对这个类的感性认识了,他的定义是在头文件MainFrm.h中,而实现则是在MainFrm.cpp文件中。所有与框架窗口向光的功能都是在这里定义和实现的。 2、 文档类及其相关的文件 文档类在应用程序中没有直观的对应关系,但是,我们应该知道的一点就是MFC的框架的一个特点就是文档/视图结构。这里可以抽象一点地来理解,比如说我们在Word中打开了一个文件,其实,这个文件就是文档,而我们看到的只不过是这个文件一个视图,所以说文档提供了应用程序显示的支持,但是我们真正看到的应用程序显示的则是一个视图,文档类的定义是在“Hello WorldDoc.h”中,而他的实现则是在“Hello WorldDoc.cpp”文件中。 3、 视图类及其相关的文件 视图类是用来显示文档对象的内容的,我们在Word程序中所看到的界面就是一个视图,我们要修改,画图首先操作的对象就是视图,所以,视图类就如他的名称所指出的那样,提供了从用户角度看到的东西。视图类的定义在“Hello WorldView.h”中,实现是在文件“Hello WorldView.h”中。 4、 应用程序类及其相关的文件 MFC应用程序的初始化,启动运行和结束都是由应用程序对象完成的。他对应的文件是”Hello World.cpp”和”Hello World.h”。 在大致的了解了应用程序对象的作用之后,现在我们来看看它们之间的关系(如下图所示)。 从上面的图中可以大致的看出MFC应用程序对象之间的关系了。应用程序一开始(此处的内容可以参考上一篇)生成应用程序对象,然后,在InitInstance中创建中将会创建文档模板对象(通过CdocManager管理),这样一来,应用程序就可以通过建立的模板对象来管理文档、视图、和框架窗口。 至此,我的这篇文章终于可以暂时告一段落了,在文中我主要分析的是应用程序的框架,所以忽略了很多的实现细节。其实,学习MFC是一个非常漫长的路,处在不同的阶段都会产生不同的看法和认识,相信随着学习的深入,每一个人都会有自己的理解。但是在这里我给出的自己的经验就是:在学习MFC的时候,一定要在宏观上对他的应用程序框架有个感性的认识!因为这样之后,我们就会在学习的时候有个明显的方向,知道自己学习的是什么东西。我在一开始的时候,就没有认识到这一点,所以往往在学习过程中,往往会不知道下一步应该做什么,也不明白自己看的东西是做什么用的。希望通过这篇文章可以与大家一起学习!