MFC全局函数开局——AfxGetApp解剖
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解剖的更多相关文章
- MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx
MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx. 函数名称 说明 AfxWinInit 被WinMain(MFC提供)调用的一个函数,用做MFC GUI程序初始化的一部分,如果 ...
- 在MFC下如何定义全局变量和全局函数
用MFC制作的工程由很多文件构成,它不能象一般C++程序那样随意在类外定义全局变量,在这里要想定义能被工程内多个文件共享的全局变量和函数必须用一些特殊方法才行.实际上有多种方法可以实现,这里只介绍两种 ...
- MFC常用函数总结
1.MFC编辑框.静态文本框相关的常用函数 <1>GetDlgItemText(ID ,str) 作用:从对话框中获取文本 第一个参数为要获取的编辑框(或者静态文本框.单选按钮等可以显示内 ...
- MFC常用函数
1.MFC的常用函数(只是找了些经常使用的,这里没有的可以CSDN查找,不需要都记住,经常使用自动就会记得) 1)GetDlgItemText(ID ,str)作用: 对话框中获取文本第一个参数为要获 ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- jQuery全局函数
全局函数是对jQuery对象的扩展,其中扩展方法包括: 一,extend扩展: //调用全局函数$(document).ready(function () { $.myFunction(); $.my ...
- 部分具有统计功能的TSQL语句(例如DBCC语句,全局函数,系统存储过程)
部分具有统计功能的TSQL语句(例如DBCC语句,全局函数,系统存储过程) 这些功能也能帮助用户了解和监控SQLSERVER的运行情况 DBCC语句,DBCC语句是SQL2005的数据库控制台命令 D ...
- JavaScript基础11——js的全局函数
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 在C++工程中设置全局函数
在头文件中对该函数进行全局函数的声明: extern void Test(); 在cpp文件中进行函数的定义: void Test() { MessageBox(NULL,L"调用了C++的 ...
随机推荐
- 由世纪互联运营的 Windows Azure 现已在中国正式发布
我们非常高兴地公开发布由世纪互联运营的 Windows Azure,这标志着我们成为第一家在中国国内正式提供公共云平台技术的跨国公司.这一伟大成就的实现,得益于 Microsoft 与世纪互联的 ...
- BZOJ 1005 明明的烦恼 (组合数学)
题解:n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数. 则 所以要求在n-2大小的数组中插入tot各序号,共有种插法: 在tot各序号排列中,插第一个节点的 ...
- Android 全屏方法
我大概不想赘述什么其他方法,我就说一下我已知在用的方法QAQ requestWindowFeature(Window.FEATURE_NO_TITLE); 设置程序无标题栏 getWindow().s ...
- Oracle 经典SQL 专为笔试准备
相信把这99条sql搞定,Oracle基本笔试简直就像玩的一样(史上最全,最经典的入门级Oracle查询语句) 1. select * from emp; 2. select empno, ename ...
- c++ 输出虚函数表内容
class Base{ public: virtual void f(){cout<<"Base::f"<<endl;} virtual void g(){ ...
- DevExpress ASP.NET 使用经验谈(8)-ASPxGridView自定义列和基本事件
为演示本节示例,我们在原来Users表增加[性别Gender].[兴趣爱好Hobbies],[CreateTime创建时间],[ModifyTime]修改时间这4个字段, ALTER TABLE [d ...
- ASP.net体系
- C#中文件管理的运用(Twelfth Day)
又到了总结的时间了,今天在云和学院学习了文件管理的一些运用及复习昨天学的里氏转换.今天我就总结下昨天遗留下的问题以及今天所学的知识. 昨天遗留的问题 里氏转换(父类转子类) 例:在这里定义父类Peop ...
- linux driver: input子系统
<韦东山Linux视频第2期_从零写驱动\第13课第1节 输入子系统概念介绍_P.wmv> 本视频对输入子系统的结构进行了详细的剖析,通过本视频,可以了解到input核心包括了设备和han ...
- 【转载】国内网站博客数据统计选免费Google Analytics还是百度统计
[转载]国内网站博客数据统计选免费Google Analytics还是百度统计 Google Analytics谷歌统计是我用的第一个网站统计工具,当然现在也一直在用.Google Analytics ...