MFC 程序来龙去脉

MFC 程序来龙去脉

——寻找与Win32 App的关联

声明

本文由张杰原创,参考了侯杰先生的《深入浅出MFC》,源码摘自 Microsoft Visual Studio 9.0\VC。 

个人能力有限,文章必定存在很多错误。我的邮箱是:chinajiezhang@gmail.com chinajiezhang@163.com  欢迎您来邮件斧正。当然您也可以加我 msn: chinazhangjie@hotmail.com 交流。

本文可供传播、交流、学习使用,但请不要用于商业用途。转载请标明此声明,谢谢您的合作。

使用Visual Studio 2008 创建一个单文档工程(对话框和多文档分析方法类似)命名为:FirstMFCDemo

我们从全局变量开始探索(理由有二:(1)全局变量在主函数之前初始化;(2) FirstMFCDemo 除了类之外其他,类总需要代码来调用吧),在  FirstMFCDemo.h 下有一个全局变量 theApp 类型为:CFirstMFCDemoApp 查看 CFirstMFCDemoApp 构造函数,构造函数为空函数,于是向其父类 CWinApp 追寻。



CWinApp —— 取代  WinMain 的地位

查看 CWinApp 源码(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afxwin.h):

class CWinApp : public CWinThread

{

// ……

HINSTANCE m_hInstance;

LPTSTR m_lpCmdLine;

int m_nCmdShow;

LPCTSTR m_pszAppName;

LPCTSTR m_pszRegistryKey;

CDocManager* m_pDocManager;

public:

LPCTSTR m_pszExeName;

LPCTSTR m_pszHelpFilePath;

LPCTSTR m_pszProfileName;

// Hooks for your initialization code

virtual BOOL InitApplication();

// overrides for implementation

virtual BOOL InitInstance();

virtual int Run();

virtual BOOL OnIdle(LONG lCount); // return TRUE if more idle processing

……

};

我们发现几行熟悉的代码:

HINSTANCE m_hInstance;

LPTSTR m_lpCmdLine;

int m_nCmdShow;

和 WinMain 的参数相同。于是我们猜测:

virtual BOOL InitApplication();

virtual BOOL InitInstance();

virtual int Run();

virtual BOOL OnIdle(LONG lCount); 

完成了窗口的注册、创建、更新、显示和运行等操作。

再看 CWinApp 父类 CWinThread 源码(c:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afxwin.h):

class CWinThread : public CCmdTarget

{

DECLARE_DYNAMIC(CWinThread)

friend BOOL AfxInternalPreTranslateMessage(MSG* pMsg);

public:

// Constructors

CWinThread();

BOOL CreateThread(DWORD dwCreateFlags = 0, UINT nStackSize = 0,

LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

// Attributes

CWnd* m_pMainWnd;       // main window (usually same AfxGetApp()->m_pMainWnd)

CWnd* m_pActiveWnd;     // active main window (may not be m_pMainWnd)

BOOL m_bAutoDelete;     // enables 'delete this' after thread termination

// only valid while running

HANDLE m_hThread;       // this thread's HANDLE

operator HANDLE() const;

DWORD m_nThreadID;      // this thread's ID

int GetThreadPriority();

BOOL SetThreadPriority(int nPriority);

// Operations

DWORD SuspendThread();

DWORD ResumeThread();

BOOL PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam);

// Overridables

// thread initialization

virtual BOOL InitInstance();

// running and idle processing

virtual int Run();

virtual BOOL PreTranslateMessage(MSG* pMsg);

virtual BOOL PumpMessage();     // low level message pump

virtual BOOL OnIdle(LONG lCount); // return TRUE if more idle processing

virtual BOOL IsIdleMessage(MSG* pMsg);  // checks for special messages

// thread termination

virtual int ExitInstance(); // default will 'delete this'

// Advanced: exception handling

virtual LRESULT ProcessWndProcException(CException* e, const MSG* pMsg);

// Advanced: handling messages sent to message filter hook

virtual BOOL ProcessMessageFilter(int code, LPMSG lpMsg);

// Advanced: virtual access to m_pMainWnd

virtual CWnd* GetMainWnd();

// Implementation

public:

virtual ~CWinThread();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

void CommonConstruct();

virtual void Delete();

// 'delete this' only if m_bAutoDelete == TRUE

public:

// constructor used by implementation of AfxBeginThread

CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam);

// valid after construction

LPVOID m_pThreadParams; // generic parameters passed to starting function

AFX_THREADPROC m_pfnThreadProc;

// set after OLE is initialized

void (AFXAPI* m_lpfnOleTermOrFreeLib)(BOOL, BOOL);

COleMessageFilter* m_pMessageFilter;

protected:

BOOL DispatchThreadMessageEx(MSG* msg);  // helper

void DispatchThreadMessage(MSG* msg);  // obsolete

};

m_pMainWnd 记录了创建窗口的句柄,等效于 Win32 App 中的hWnd

CFrameWnd CMainFrame的父类)—— 取代 WndProc 的地位

查看  CMainFrame 源码:

class CMainFrame : public CFrameWnd

{

protected// 仅从序列化创建

CMainFrame();

DECLARE_DYNCREATE(CMainFrame)

public:

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

// 实现

public:

virtual ~CMainFrame();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:  // 控件条嵌入成员

CStatusBar  m_wndStatusBar;

CToolBar    m_wndToolBar;

// 生成的消息映射函数

protected:

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

DECLARE_MESSAGE_MAP()

};

可以猜测出  OnCreate 响应的是 WM_CREATE 消息。 但是怎样将 OnCreate 和 WM_CREATE 消息或者说和 Window Produce 联系起来呢? 方法是利用上面几个神秘的宏……

查看 CWinApp的构造函数(C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\appcore.cpp):

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

}

请看:

AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

pModuleState->m_pCurrentWinApp = this;

查看 _AFX_CMDTARGET_GETSTATE();源码:

#ifdef _AFXDLL

#define _AFX_CMDTARGET_GETSTATE() (m_pModuleState)

#else

#define _AFX_CMDTARGET_GETSTATE() (AfxGetModuleState())

#endif

可以发现 _AFX_CMDTARGET_GETSTATE() 最终被 m_pModuleState 替换。而 m_pModuleState 是 CCmdTarget 的成员,CCmdTarget 是 CWinApp 的父类,因此 m_pModuleState 也是 theApp 的一部分。

查看 AFX_MODULE_STATE 的定义:

class AFX_MODULE_STATE : public CNoTrackObject

{

public:

#ifdef _AFXDLL

AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,

BOOL bSystem = FALSE);

#else

explicit AFX_MODULE_STATE(BOOL bDLL);

#endif

~AFX_MODULE_STATE();

CWinApp* m_pCurrentWinApp;

HINSTANCE m_hCurrentInstanceHandle;

HINSTANCE m_hCurrentResourceHandle;

LPCTSTR m_lpszCurrentAppName;

BYTE m_bDLL;    // TRUE if module is a DLL, FALSE if it is an EXE

BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not

BYTE m_bReserved[2]; // padding

DWORD m_fRegisteredClasses; // flags for registered window classes

// runtime class data

#ifdef _AFXDLL

CRuntimeClass* m_pClassInit;

#endif

CTypedSimpleList<CRuntimeClass*> m_classList;

// OLE object factories

#ifndef _AFX_NO_OLE_SUPPORT

#ifdef _AFXDLL

COleObjectFactory* m_pFactoryInit;

#endif

CTypedSimpleList<COleObjectFactory*> m_factoryList;

#endif

// number of locked OLE objects

long m_nObjectCount;

BOOL m_bUserCtrl;

// AfxRegisterClass and AfxRegisterWndClass data

CString m_strUnregisterList;

#ifdef _AFXDLL

WNDPROC m_pfnAfxWndProc;

DWORD m_dwVersion;  // version that module linked against

#endif

// variables related to a given process in a module

//  (used to be AFX_MODULE_PROCESS_STATE)

void (PASCAL *m_pfnFilterToolTipMessage)(MSG*, CWnd*);

#ifdef _AFXDLL

// CDynLinkLibrary objects (for resource chain)

CTypedSimpleList<CDynLinkLibrary*> m_libraryList;

// special case for MFCXXLLL.DLL (localized MFC resources)

HINSTANCE m_appLangDLL;

#endif

#ifndef _AFX_NO_OCC_SUPPORT

// OLE control container manager

COccManager* m_pOccManager;

// locked OLE controls

CTypedSimpleList<COleControlLock*> m_lockList;

#endif

#ifndef _AFX_NO_DAO_SUPPORT

_AFX_DAO_STATE* m_pDaoState;

#endif

#ifndef _AFX_NO_OLE_SUPPORT

// Type library caches

CTypeLibCache m_typeLibCache;

CTypeLibCacheMap* m_pTypeLibCacheMap;

#endif

// define thread local portions of module state

CThreadLocal<AFX_MODULE_THREAD_STATE> m_thread;

//Fusion: declare pointer to array of pointers to isolation aware dll wrappers (ex: comctl32).

CDllIsolationWrapperBase** m_pDllIsolationWrappers;

//Defaults to TRUE. When FALSE - MFC will not activate context in AFX_MAINTAIN_STATE2 (used by AFX_MANAGE_STATE).

BOOL m_bSetAmbientActCtx;

//Handle of the module context.

HANDLE m_hActCtx;

void CreateActivationContext();

// bool indicating the return value of InitNetworkAddressControl() (from shell32.dll) 

BOOL m_bInitNetworkAddressControl;

// bool indicating whether or not InitNetworkAddressControl() (from shell32.dll) have been called for CNetAddressCtrl

BOOL m_bInitNetworkAddressControlCalled;

};

又可以发现 AFX_MODULE_STATE 的成员m_pCurrentWinApp 的 类型是 CWinApp* 。 

由此观之, 

pModuleState->m_pCurrentWinApp = this; 

解释为用 CWinApp 中的一个CWinApp指针变量来存储自己派生类对象的地址。 等效于:

theApp.m_pCurrentWinApp = &theApp;

隐晦不明的 WinMain 

theApp 完成初始化以后,WinMain 登场。WinMain 通过链接器直接加到应用程序代码中。查看 WinMain 源码(C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\appmodul.cpp):

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

_In_ LPTSTR lpCmdLine, int nCmdShow)

#pragma warning(suppress: 4985)

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

查看 AfxWinMain 源码(C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\winmain.cpp): 

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

_In_ 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)

{

TRACE(traceAppMsg, 0, "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)

{

TRACE(traceAppMsg, 0, "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();

AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

pApp->InitApplication()

pThread->InitInstance()

nReturnCode = pThread->Run();

我们分块来探究:

1CWinThread* pThread = AfxGetThread(); 和 CWinApp* pApp = AfxGetApp()

2AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

3pApp->InitApplication()

4pThread->InitInstance()

5nReturnCode = pThread->Run()

5步完成了:窗口的初始化,注册、创建、更新和显示、运行(消息循环)。等窗口接收到 WM_QUIT 消息,之后窗口关闭。



posted @ 2011-09-19 23:58  独酌逸醉  阅读(2557)  评论(0编辑  收藏  举报