MFC中有不少的全局函数,方便在不同对象中获取不同的内容或创建不同的对象。主要全局函数有:

AfxWinInit() AfxBeginThread() AfxEndThread() AfxFormatString1() AfxFormatString2()

AfxMessageBox()   AfxOutPutDebugString()   AfxGetApp() AfxGetMainWnd() AfxGetInstance()

AfxRegisterClass()

这些函数从名称上可见豹斑(功能)。

本文是学习深入浅出MFC后的第一个笔记,解析AfxGetApp()函数

在AFXWIN.H中是这么定义的:

CWinApp* AFXAPI AfxGetApp();

那么AfxGetApp是怎么获取当前App的CWinApp类指针呢?

AfxGetApp是一个内联函数,其实现如下(在AFXWIN1.INL):

_AFXWIN_INLINE CWinApp *AFXAPI AfxGetApp()

{ return afxCurrentWinApp;}

而afxCurrentWinApp是一个宏,定义在AFXWIN.H中:

#define afxCurrentWinApp    AfxGetModuleState()->m_pCurrentWinApp

AfxGetModuleState返回的是一个:AFX_MODULE_STATE类的指针(AFXSTAT_.H):

AFX_MODULE_STATE* AFXAPI AfxGetModuleState();

在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

转了这么多,自己都迷糊了,AFX_MODULE_STATE什么时候被初始化了,AfxGetModuleState又都干了些什么,不然怎么可 能调用AfxGetModuleState()->m_pCurrentWinApp获得当前窗口的App呢?最有可能被初始化的地方是在构造函数 之中。而我们获取的是App类型的指针,而App是继承之CWinApp类的。因此下面我们看看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;     //又将this指针传给了m_pCurrentWinApp,哦呵呵……
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
}

CWinApp的构造函数申明了一个AFX_MODULE_STATE类的指针,里面通过this指针填充了AFX_MODULE_STATE指针中的部分内容。下面我们再来看看CWinApp中的_AFX_CMDTARGET_GETSTATE()又是什么:

#ifdef _AFXDLL
#define _AFX_CMDTARGET_GETSTATE() (m_pModuleState)
#else
#define _AFX_CMDTARGET_GETSTATE() (AfxGetModuleState())
#endif

如果此处不考虑_AFXDLL情况,那么在CWinApp中将直接调用 AfxGetModuleState()函数,瞧,又是AfxGetModuleState()函数。于是我们可以这么考虑,在内存中有一份全局或静态的 AFX_MODULE_STATE类,AfxGetModuleState只是返回这一份全局指针(猜测)。在CWinApp中通过对AFX_MODULE_STATE中的m_pCurrentWinApp填充this指针后,将使全局的AFX_MODULE_STATE保存当前WinApp中的CWinApp指针。

其中的特殊指之处在于使用了this指针,当基类被继承后,this指针将代表继承类的this指针。因此任何一个CWinApp被继承后,如继承类为CMyWinApp,那么 CMyWinApp的地址将被存在AFX_MODULE_STATE的全局变量之中,当使用AfxGetModuleState()函数获取 AFX_MODULE_STATE时便可获取当前系统的CMyWinApp指针m_pCurrentWinApp。

下面总结一下:

当前指针通过AfxGetApp()通过返回afxCurrentWinApp,而afxCurrentWinApp宏为AfxGetModule()- >m_pCurrentWinApp,即AfxGetApp()通过返回AfxGetModule()->m_pCurrentWinApp 获取当前App的指针,而AfxGetModule()->m_pCurrentWinApp指针通过CWinAPP构造函数通过this指针设 置,而this指针恰恰就是当前App的指针(this将转换为继承类的指针)。

因此也就解释了不管当前App被怎么继承,AfxGetModule()->m_pCurrentWinApp始终能够获取当前App的指针的原因了。

MFC全局函数开局——AfxGetApp解剖的更多相关文章

  1. MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx

    MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx. 函数名称 说明 AfxWinInit 被WinMain(MFC提供)调用的一个函数,用做MFC GUI程序初始化的一部分,如果 ...

  2. 在MFC下如何定义全局变量和全局函数

    用MFC制作的工程由很多文件构成,它不能象一般C++程序那样随意在类外定义全局变量,在这里要想定义能被工程内多个文件共享的全局变量和函数必须用一些特殊方法才行.实际上有多种方法可以实现,这里只介绍两种 ...

  3. MFC常用函数总结

    1.MFC编辑框.静态文本框相关的常用函数 <1>GetDlgItemText(ID ,str) 作用:从对话框中获取文本 第一个参数为要获取的编辑框(或者静态文本框.单选按钮等可以显示内 ...

  4. MFC常用函数

    1.MFC的常用函数(只是找了些经常使用的,这里没有的可以CSDN查找,不需要都记住,经常使用自动就会记得) 1)GetDlgItemText(ID ,str)作用: 对话框中获取文本第一个参数为要获 ...

  5. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  6. jQuery全局函数

    全局函数是对jQuery对象的扩展,其中扩展方法包括: 一,extend扩展: //调用全局函数$(document).ready(function () { $.myFunction(); $.my ...

  7. 部分具有统计功能的TSQL语句(例如DBCC语句,全局函数,系统存储过程)

    部分具有统计功能的TSQL语句(例如DBCC语句,全局函数,系统存储过程) 这些功能也能帮助用户了解和监控SQLSERVER的运行情况 DBCC语句,DBCC语句是SQL2005的数据库控制台命令 D ...

  8. JavaScript基础11——js的全局函数

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. 在C++工程中设置全局函数

    在头文件中对该函数进行全局函数的声明: extern void Test(); 在cpp文件中进行函数的定义: void Test() { MessageBox(NULL,L"调用了C++的 ...

随机推荐

  1. Android源码的下载和编译

    由于公司会安排我做硬解码这块,所以最近一直想研究一下Android源码,可是Android源码的下载真的挺麻烦的(可能是我第一次下载),参照网上的方法,没有一个可行的,现在就将我的下载过程和大家分享一 ...

  2. Modular Inverse(模逆元,扩展欧几里德)

    Modular Inverse Time Limit: 2 Seconds      Memory Limit: 65536 KB The modular modular multiplicative ...

  3. US/OS2之任务同步与通信

    嵌入式系统中的各个任务都是以并发的方式来运行的,并为同一个大的任务服务,它们不可避免地要共同使用一些共享资源,并且在处理一些需要多个任务共同协作来完成的工作时,还需要相互的支持和限制.因此,对于一个完 ...

  4. Asp.Net MVC4.0 官方教程 入门指南之二--添加一个控制器

    Asp.Net MVC4.0 官方教程 入门指南之二--添加一个控制器 MVC概念 MVC的含义是 “模型-视图-控制器”.MVC是一个架构良好并且易于测试和易于维护的开发模式.基于MVC模式的应用程 ...

  5. gcc代码反汇编查看内存分布[2]: arm-linux-gcc

    arm-none-linux-gnueabi-gcc -v gcc version 4.4.1 (Sourcery G++ Lite 2010q1-202) 重点: 代码中的内存分配, 地址从低到高: ...

  6. C、C++中“*”操作符和“后++”操作符的优先级

    假设有如下的定义 char carr[] = {"test"}; char cp = carr; 那么表达式 *cp++; 的右值是什么呢? 这个表达式在数组遍历的程序中非常常见, ...

  7. block, inline和inline-block的区别

    display:block元素的特点是:总是在新行上开始:高度,行高以及顶和底边距都可控制:宽度缺省是它的容器的100%,除非设定一个宽度<div>, <p>, <h1& ...

  8. [javascript]MooTools Selectors(MooTools 选择器) ELEMENT DOM选择

    //ELEMENT DOM选择//on are tag names. //All the divs on the page: $$('div'); //All the divs and paragra ...

  9. HTTP协议一次上传多个文件的方法

    如何通过HTTP协议一次上传多个文件呢?在这里有两个思路,是同一个方法的两种实现.具体程序还需自己去设计 1. 在form中设置多个文件输入框,用数组命名他们的名字,如下: < form act ...

  10. centos主机建立ssh互信

    ssh-keygen 生成密钥 1.ssh-keygen -t rsa 可以加密和签名 rsa 只能加密不能签名 2.ssh-copy-id -i /root/.ssh/id_rsa.pub USER ...