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. CCPC A(模拟)

    Secrete Master Plan Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Othe ...

  2. CF 192 Div2

    A.Cakeminator 暴搞之,从没有草莓覆盖的行.列遍历 char map[30][30]; int vis[30][30]; int hang[30],lie[30]; int main() ...

  3. Android ScrollView嵌套HorizontalScrollView 滑动问题 ScrollView包括GridView显示问题

    今天项目使用到ScrollView嵌套HorizontalScrollView,ScrollView里包括GridView,发现几个问题非常经典.在此记录: 问题1.ScrollView嵌套Horiz ...

  4. GDB命令行最基本操作

    程序启动: A.冷启动 gdb program              e.g., gdb ./cs gdb –p pid                 e.g., gdb –p `pidof c ...

  5. css两列布局,一边固定宽度,另一边自适应

    <!DOCTYPE HTML><HTML>    <head>                <meta charset="utf-8" ...

  6. C# Best Practices - Building Good Classes

    Building a Class The last four refer as members Signature Accessiblity modifier (Default:internal) c ...

  7. NOIP2015前

    时间过得好快...明天就要出发去NOIP了...然后再过半年就要省选了....希望自己能取得好成绩吧... NOIP2015 bless all !

  8. Android操作HTTP实现和服务器通信

    众所周知,Android与服务器通信通常采用HTTP通信方式和Socket通信方式,而HTTP通信方式又分get和post两种方式.至于Socket通信会在以后的博文中介绍. HTTP协议简介: HT ...

  9. linux安装LNMP的资源

    wget http://nginx.org/download/nginx-0.7.69.tar.gz wget http://museum.php.net/php5/php-5.2.10.tar.gz ...

  10. JS 随记

    一.在内联框架中,刷新整个框架,在.net中使用此方法( ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "re ...