一、Win32Application Architecture
一个Win32 Application Architecture的代码结构如下:
LRESULT CALLBACK WinWordsProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); //定义回调处理消息函数 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){ // 创建一个窗口类分为三步:1.设计窗口类 2.注册窗口类 3.创建窗口 4.显示及更新窗口 // 步骤1.设计窗口类 WNDCLASS wc; …… // 步骤2:注册窗口类 RegisterClass(&wc); // 步骤3:创建窗口 HWND hw = NULL; hw = CreateWindow("Icanth2011", "My Fist Win32 Application Project!~", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 600, 400, NULL, NULL, hInstance, NULL); // 步骤4:显示及更新窗口 ShowWindow(hw, SW_SHOWNORMAL); UpdateWindow(hw); // 消息循环 MSG msg; BOOL bRet; while((bRet=GetMessage(&msg, NULL, 0, 0))!=0){ if(-1 == bRet){ return -1; } TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } | |
由此可见,Win32 Application 程序的组成分为如下几个部分:
1. 找到WinMain程序入口,并开始执行
2. 创建并设计窗口类
3. 注册窗口类
4. 创建窗口
5. 显示及更新窗口
6. 循环获取消息,经处理,交还系统让其调用相关回调消息处理函数进行处理。
二、MFCArchitecture
由于Windows API过多,不方便程序员使用,并且非面对象。于是MFC被用于对Windows API进行封装,MFC始终实际运行过程就是Win32 Application程序的运行过程。
1. MFC的项目结构
利用MFC AppWipzard自动生成的项目包括五个文件:CMyFirstMFCApp、CMainFrame、CFirstMFCDoc、CMyFirstCView、CAboutDlg。CMyFirstMFCApp继承自CWinApp,CMainFrame、CMyFirstCView、CAboutDlg都继承自CWnd,CFirstMFCDoc继承自CDocument,体现“文档/视图”结构。其项目结构如下所示:
2. MFC的执行过程
对于MFC框架运行过程进行剖析,最好的资料是MFC源代码,VC6位于“\Microsoft Visual Studio\VC98\MFC\SRC”下。执行过程如下:
定义theApp(:CMyFistMFCApp) ——>执行构造函数:CWinApp()->CMyFistMFCApp()-> ——>程序入口_tWinMain (宏,定义为WInMain) ——>执行AftxWinMain | |
2.1 MFC的WinMain
在\SRC\APPMODUL.CPP中,可找到如下代码:
MFC\SRC\APPMODUL.CPP: extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // call shared/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } | |
而其中_tWinMain其实就是WinMain函数的宏,定义如下:
#define _tmain main #define _tWinMain WinMain #ifdef _POSIX_ #define _tenviron environ | |
由此可见,WinMain中调用AfxWinMain进行处理。MFC包含此文件,故将找到此入口并自动调用执行。
2.2 theApp全局对象
在Project\CMyFirstMFCApp.CPP中,可找到一行代码发下:
Project\CMyFirstMFCApp.CPP: / // The one and only CMyFistMFCApp object CMyFistMFCApp theApp; | |
当定义theApp时,将先执行CWinApp(\MFC\SRC\APPCORE.CPP)的构造函数:
\MFC\SRC\APPCORE.CPP: CWinApp::CWinApp(LPCTSTR lpszAppName) // 有在该类定义时有默认值NULL { if (lpszAppName != NULL) m_pszAppName = _tcsdup(lpszAppName); else m_pszAppName = NULL; // initialize CWinThread state AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE(); AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread; 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; // handle,this代表子类CMyFirstMFCApp对象 ASSERT(AfxGetApp() == this); …… } | |
2.3 AfxWinMain(WINMAIN.CPP)
1.AfxWindMain定义
\MFC\SRC\WINMAIN.CPP: int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp(); if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) if (pApp != NULL && !pApp->InitApplication()) goto InitFailure; if (!pThread->InitInstance()) { if (pThread->m_pMainWnd != NULL) { pThread->m_pMainWnd->DestroyWindow(); } goto InitFailure; } nReturnCode = pThread->Run(); } | |
2.AfxGetThread
AfxGetThread(THRDCORE.CPP)中调用AfxGetApp,和afxGetApp返回同值,代码如下所示:
\MFC\SRC\ THRDCORE.CPP: CWinThread* AFXAPI AfxGetThread() { // check for current thread in module thread state AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); CWinThread* pThread = pState->m_pCurrentWinThread; // if no CWinThread for the module, then use the global app if (pThread == NULL) pThread = AfxGetApp(); return pThread; } | |
3.AfxGetApp
AfxGetApp(AFXWIN1.INL)中定义:
AFXWIN1.INL: _AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp(){ return afxCurrentWinApp; } | |
而afxCurrentWinApp定义位于AFXWIN.H文件中,如下:
AFXWIN.H: #define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp | |
即为CWinApp构造函数时初始化为this的m_pCurrentWinApp。
4.InitInstance
类CWinAPP(APPCORE.CPP)中InitInstance函数定义为:
\MFC\SRC\ APPCORE.CPP: // overrides for implementation virtual BOOL InitInstance(); | |
类InitInstance即为虚函数,根据多态性,将调用CMyFirstMFCApp类的InitInstance。
2.4 InitInstance(CMyFirstMFCAPP.CPP)
\MFC\SRC\ CMyFirstMFCAPP.CPP: BOOL CMyFistMFCApp::InitInstance() { CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMyFistMFCDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CMyFistMFCView)); AddDocTemplate(pDocTemplate); m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); } | |
2.5 MFC框架窗口
CFirstMyMFC有两个窗口,其中一个是CMainFrame。
2.5.1 设计和注册窗口
1. CMainFrame::PreCreateWindow定义(\Project\CMainFrame.cpp)
\MFC\SRC\ CMyFirstMFCAPP.CPP: BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; return TRUE; } | |
2. CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) (\MFC\SRC\WINFRM.CPP)
\MFC\SRC\ CMyFirstMFCAPP.CPP: BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) { if (cs.lpszClass == NULL) { VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background } return TRUE; } | |
其中,AfxDeferRegisterClass即为AfxEndDeferRegisterClass的宏定义,位于AFXIMPL.H文件中:
AFXIMPL.H: #define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass) | |
3. AfxEndDeferRegisterClass (位于WINCORE.CPP中)
此处指定DefWindowProc函数来处理回调消息。 (!~)
MFC\SRC\WINCORE.CPP: BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister) { // mask off all classes that are already registered AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); fToRegister &= ~pModuleState->m_fRegisteredClasses; if (fToRegister == 0) return TRUE; LONG fRegisteredClasses = 0; // common initialization WNDCLASS wndcls; memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults wndcls.lpfnWndProc = DefWindowProc; wndcls.hInstance = AfxGetInstanceHandle(); wndcls.hCursor = afxData.hcurArrow; INITCOMMONCONTROLSEX init; init.dwSize = sizeof(init); // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go if (fToRegister & AFX_WND_REG) { // Child windows - no brush, no icon, safest default class styles wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wndcls.lpszClassName = _afxWnd; if (AfxRegisterClass(&wndcls)) fRegisteredClasses |= AFX_WND_REG; } …… } | |
4. AfxRegisterClass (位于WINCORE.CPP中)
MFC\SRC\WINCORE.CPP: BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass) { WNDCLASS wndcls; if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName, &wndcls)) { // class already registered return TRUE; } if (!::RegisterClass(lpWndClass)) { TRACE1("Can't register window class named %s\n", lpWndClass->lpszClassName); return FALSE; } return TRUE; } | |
2.5.2 创建窗口
1. CFrameWnd::Create (WINFRM.CPP)
MFC\SRC\WINFRM.CPP: BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) { HMENU hMenu = NULL; if (lpszMenuName != NULL) { // load in a menu that will get destroyed when window gets destroyed HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU); if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL) { TRACE0("Warning: failed to load menu for CFrameWnd.\n"); PostNcDestroy(); // perhaps delete the C++ object return FALSE; } } m_strTitle = lpszWindowName; // save title for later if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) { TRACE0("Warning: failed to create CFrameWnd.\n"); if (hMenu != NULL) DestroyMenu(hMenu); return FALSE; } return TRUE; } | |
3. CWnd:CreateEx (WINCORE.CPP)
MFC\SRC\WINFRM.CPP: 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) { // allow modification of several common create parameters CREATESTRUCT cs; cs.dwExStyle = dwExStyle; …… if (!PreCreateWindow(cs)) //完成注册窗口类工作 { PostNcDestroy(); return FALSE; } AfxHookWindowCreate(this); HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); …… } | |
以下是CREATESTRUCT和CreateWindowEx参数的对比:
由于CREATESTRUCT中的属性都定义为指针,故可在PreCreateWindow中更改属性,在CreateWindowEx中将更改显示。
4. MFC的调用关系
① theApp
theApp(CMyFirstMFCApp.CPP) ——> CWinAPP ::CWinAPP(){ pModuleState->m_pCurrentWinApp = this; } | |
② _tWinMain(APPMODUL.CPP)
_tWinMain () { AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } | |
③ AfxWinMain(WinMain.CPP)
int AFXAPI AfxWinMain() { CWinThread* pThread = AfxGetThread(); //——>return AfxGetApp() (:THRDCORE.CPP) CWinApp* pApp = AfxGetApp(); //——>return afxCurrentWInApp (:AFXWIN1.INL) //——>return AfxGetModuleState()->m_pCurrentWinApp (:AFXWIN.H) AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow); pApp->InitApplication(); pThread-> InitInstance (); //——> CMyFirstMFCApp::InitInstance //——> AddDocTemplate(pDocTemplate); //——> m_pMainWnd->ShowWindow(SW_SHOW); //——> m_pMainWnd->UpdateWindow(); pThread->Run(); } | |
④ 窗口
设计和注册窗口:
CMainFrame::PreCreateWindow (\Project\ CMainFrame.cpp) ——>CFrameWnd::PreCreateWindow ——>AfxDeferRegisterClass(宏= AfxEndDeferRegisterClass) ——>AfxEndDeferRegisterClass ——>AfxRegisterClass ——>::RegisterClass (SDK) | |
创建窗口:
CFrameWnd::Create()
——>CFrameWnd::CreateEx()
——>CWnd::CreateEx()
——>virsual CWnd::PreCreateWIndow(虚函数,调用子类中CFrameWnd:: PreCreateWIndow),
:: CreateWIndowEx()