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();

我们分块来探究:

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

(2)AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

(3)pApp->InitApplication()

(4)pThread->InitInstance()

(5)nReturnCode = pThread->Run()

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

转载于:https://www.cnblogs.com/chinazhangjie/archive/2011/09/19/2181954.html

MFC 程序来龙去脉相关推荐

  1. MFC程序的剖析及生死因果揭秘

    本文剖析MFC底层的程序脉络,主要是由MFC深入浅出的学习笔记而得. SDK下Windows程序的编程:对于一般SDK下Windows程序的编程,其主要步骤如下: 各步骤说明: 1:WinMain函数 ...

  2. MFC程序的生死因果

    MFC程序的来龙去脉(causal relations)  MFC的程序如何运行,第一件事情就是找出MFC程序的进入点.MFC程序也是Windows程序.所以它应该也有一个WinMain.但在程序中好 ...

  3. 六、MFC 程序的生死因果 (学习笔记)

    MFC程序的生死因果 项目HELLO 理想如果不向实际做点妥协,理想就会归于尘土. 中华民国还得十次革命才得建立,对象导向怎能把一切传统都抛开. 以传统的C/SDK 撰写Windows 程序,最大的好 ...

  4. 基于Dialog的MFC程序在启动时隐藏为托盘程序(四)

    这部分说一下如何加menu..如果做小气球.. mfc的menu确是不如C#活着java那么easy.. 首先在rc里添加menu资源..然后在ui界面里先设置一下你的菜单.. 在第(二)部分已经简单 ...

  5. MFC程序的框架理解

    一直使用MFC编写GUI程序,微软封装太多,生成的程序让人有一种不知道其出处的感觉,整体的框架还是需要推敲,下面的文章讲得挺好的,至少要知道MFC程序的开头和结束,这样就能在开头初始化一些我们需要的东 ...

  6. mfc程序转化为qt_工控编程,Qt 学习之路

    Qt 是一个著名的 C++ 库--或许并不能说这只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI.使用 Qt,在一定程序上你获得的是一个"一站式"的服务:不再需要研究 ...

  7. mfc 内嵌 本地html,MFC程序中内嵌网页,附示例工程

    最近在课程设计,因为小悠太懒了,是在不想用C++完成一些简单的文件上传下载操作,于是就想着将网页内嵌到程序中,上传下载神马的就直接使用网页Web来完成就好了,本示例中将演示在MFC程序中内嵌一个htm ...

  8. VC MFC程序,在About对话框中获取并显示程序的版本号

    =================================================本文为HeYuanHui原作 转载必须确保本文完整并完整保留原作者信息及本文原始链接! NN:     ...

  9. DbgView软件 查看VC++ MFC 程序的打印信息

    DbgView软件 查看VC++ MFC 程序的打印信息 一.在写VC++ MFC程序的调制过程中,需要跟踪打印信息,但在MFC中用printf不知道在哪里看打印信息,今天介绍一款软件,可以查看对应的 ...

最新文章

  1. liigo:爱可视70平板电脑使用感受,遗憾与满足并存
  2. java动态内存分部,如何利用Java实现动态内存分配?
  3. MySQL高可用--MGR入门(1)单主/多主模式搭建
  4. db2 linux 导入数据_实现DB2数据库迁移之导入步骤在Linux下
  5. 【Qt串口调试助手】1.0 - 400行代码撸一个Qt5串口调试助手框架
  6. 学开发的基本规范和要求
  7. java 声明数组_Java中的数组简介
  8. 给构造函数(constructor)创建对象(object)
  9. 十分钟教你使用NoteExpress
  10. LaTex - PPT 模板-3 (亲测可用)
  11. 标准二维表问题 (卡特兰数)
  12. USGS 官方批量下载软件bda 安装问题
  13. 显示前半内容后半内容用省略号_220六语文课文内容填空与句子练习
  14. Scheme语言学习---求解三个数中其中两个较大数的和
  15. 基于python下django框架 实现校园排课选课系统详细设计
  16. 基于jsp+mysql+Spring+mybatis java的SSM健身房管理系统
  17. VR全景有什么应用,和传统摄影的区别,发展前景如何?
  18. 企业邮箱密码怎么找回?
  19. pytest与coverage联合使用
  20. 智能家居论文文献_智能家居文献综述范文

热门文章

  1. mpp文件转换excel_原来只要按下这个键,Word、PDF、PPT、Excel文件随你互相转换
  2. 试述hadoop生态系统以及每个部分的具体功能_Hadoop在大数据分析中的意义和作用...
  3. 哈工大大数据实验_【新闻动态】南京大学PASA大数据实验室在KDD Cup 2020 AutoGraph自动化图数据建模国际挑战赛中荣获第二名...
  4. Java讲课笔记24:字节流
  5. MyBatis使用MySQL存储过程
  6. 【codevs1037】取数游戏,博弈
  7. 【BZOJ1010】【codevs1319】玩具装箱,斜率优化DP
  8. 将来时的条件句_58
  9. dh算法 理论依据_DH算法原理
  10. 2017.9.28 lca 失败总结