APPMODUL.cpp中的WinMain函数:
// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // export WinMain to force linkage to this module extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow); extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // call shared/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } ///////////////////////////////////////////////////////////////////////////// // initialize app state such that it points to this module's core state BOOL AFXAPI AfxInitialize(BOOL bDLL, DWORD dwVersion) { AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); pModuleState->m_bDLL = (BYTE)bDLL; ASSERT(dwVersion <= _MFC_VER); UNUSED(dwVersion); // not used in release build #ifdef _AFXDLL pModuleState->m_dwVersion = dwVersion; #endif #ifdef _MBCS // set correct multi-byte code-page for Win32 apps if (!bDLL) _setmbcp(_MB_CP_ANSI); #endif //_MBCS return TRUE; } // force initialization early #pragma warning(disable: 4074) #pragma init_seg(lib) #ifndef _AFXDLL void AFX_CDECL _AfxTermAppState() { // terminate local data and critical sections AfxTermLocalData(NULL, TRUE); AfxCriticalTerm(); // release the reference to thread local storage data AfxTlsRelease(); } #endif #ifndef _AFXDLL char _afxInitAppState = (char)(AfxInitialize(FALSE, _MFC_VER), atexit(&_AfxTermAppState)); #else char _afxInitAppState = (char)(AfxInitialize(FALSE, _MFC_VER)); #endif /////////////////////////////////////////////////////////////////////////////
#define _tWinMain WinMain _tWinMain 实际上是一个宏,展开之后就是WinMain函数。
找到了WinMain函数,那么它是如何与MFC程序中的各个类组织在一起的呢?
全局变量-》testApp构造函数-》WinMain函数
无论全局变量还是全局对象,程序在运行时,在加载main函数之前,就已经为全局变量或全局对象分配了内存空间。对一个全局对象来说,此时就会调用该对象的构造函数,构造该对象,并进行初始化操作。
每一个MFC程序有且有一个从应用程序类(CWinAPP)派生的类。每一个MFC程序实例有且有一个派生类的实例化对象,也就是theApp全局对象。该对象就表示了应用程序本身。
CTestApp theApp;当一个子类在构造之前会先调用其父类的构造函数。因此theApp对象构造函数CTestApp在调用之前,会调用其父类CWinApp的构造函数,从而就把我们程序自己创建的类与Microsoft提供的基类联起来了。
关于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(); 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; ASSERT(AfxGetApp() == this); // in non-running state until WinMain m_hInstance = 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_nSafetyPoolSize = 512; // default size }
pThreadState->m_pCurrentWinThread = this;
根据C++继承性原理,这个this对象代表的是子类CTestapp的对象,即theapp.同时,可以发现CWinApp的构造函数有个LPCTSTR类型的形参:lpszAppName.但是我们程序中CTestApp的构造函数式没有参数的。在第二章介绍C++编程知识时,曾经介绍,如果基类的构造函数带有一个形参,那么子类构造函数需要显示地调用基类带参数的构造。
如果基类的构造函数带有一个形参,那么子类构造函数需要显式地调用基类带参数的构造函数。那么,为什么我们程序中的CTestApp构造函数没有这么做呢?
我们知道,如果某个函数的参数有默认值,那么在调用该函数时可以传递该参数的值,也可以不传递,直接使用默认即可。CWinApp类的定义:
class CWinApp : public CWinThread { DECLARE_DYNAMIC(CWinApp) public: // Constructor CWinApp(LPCTSTR lpszAppName = NULL); // app name defaults to EXE name
............................
CWinApp构造函数的形参确实有一个默认值(NULL)。这样,在调用CWinApp类的构造函数时,就不用显示的去传递这个参数的值。
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // call shared/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); }
可以发现,WinMain函数时间上是通过AfxWinMain函数来完成它的功能的。
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { ASSERT(hPrevInstance == NULL); int nReturnCode = -1; 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: #ifdef _DEBUG // Check for missing AfxLockTempMap calls if (AfxGetModuleThreadState()->m_nTempMapLock != 0) { TRACE1("Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock); } AfxLockTempMaps(); AfxUnlockTempMaps(-1); #endif AfxWinTerm(); return nReturnCode; } /////////////////////////////////////////////////////////////////////////////
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
AfxWinMain首先调用AfxGetThread函数获得一个CWinTHread类型的指针,接着调用AfxGetApp函数获得一个CWinApp类型的指针。
对test程序来说,pThread和pApp所指向的都是CTestApp类的对象,即theApp全局对象。
接下来调用三个函数完成Win32程序所需要的几个步骤:设计窗口类、注册窗口类、创建窗口、显示窗口、更新窗口、消息循环、以及窗口过程函数。
InitApplication函数 该函数完成MFC内部管理方面的工作。接着,调用pThread的InitInstance函数。在Test程序中,可以发现从CWinApp派生的应用程序类CTestApp也有一个InitInstance函数,其声明代码如下所示:
virtual BOOL InitInstance();
该函数为虚函数,根据类的多态性原理,可以知道AfxWinMain函数这里实际上调用的是子类CTestApp的InitInstace函数
BOOL CTestApp::InitInstance() { AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif // 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(CTestDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CTestView)); 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; }
我们创建的mfc应用程序Test,实际上有两个窗口。其中一个是CMainFrame类对象所代表的应用程序框架窗口。该类有一个PreCreateWindow函数,这是在窗口产生之前被调用的。该函数默认实现代码如下:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return TRUE; }
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) { if (cs.lpszClass == NULL) { VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background } if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4) cs.style |= FWS_PREFIXTITLE; if (afxData.bWin4) cs.dwExStyle |= WS_EX_CLIENTEDGE; return TRUE; }
在initinstance中:
m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();
显示应用程序框架窗口和更新这个窗口。
消息循环:
在AfxWinMain函数实现代码:
nReturnCode = pThread->Run();
窗口类 窗口对象 窗口 的关系!