MFC有哪些机制

各有什么用

MFC程序运行机制
学MFC,竟然还不知道MFC的MAIN函数在什么地方?怎么运行的?实在不高明。
看过候捷(JJHOU)老师的《深入浅出MFC》的,对它一定很熟悉。呵呵,本文是献给没有看过那本书,但是又很希望学习MFC程序设计的朋友的。(没有看过那本书的朋友还不赶快去买?)其实本文,主要是对《深入浅出MFC》第六章的一个总结和补充罢了!(本文有该书不同的地方,也有一些笔者自己的见解!)
言归正传。
假如你用AppWizard一步一步NEXT下来,然后在CLASSVIEW中去找寻WINMAIN函数,那么你只有失望。MFC最大的特点是什么?封装!MFC的确封装的太好了,以至于很多想学习MFC的人都望而却步。闲话少说,还是继续我们今天的话题,MAIN函数!实话告诉你吧,即使你搜索所有的MFC生成的文件,都无法发现WINMAIN的字眼,那么它就近在什么地方呢?
我相信你已经想到,MAIN函数应该在主要的应用程序文件中。难道是“您定义的程序名.cpp”这个文件?不错就是它。再Crtl+F一下,看有没有我们要找的WINMAIN函数?看来你又要失望了,但是你注意有这样一句:

/////////////////////////////////////////////////////////////////////////////
// The one and only CMyApp object

CMyApp theApp; //本人建立的工程名为My。

是不是很特别,再注意一下那句注释“The one and only CMyApp object”,每个应用程序有且只用一个CMyApp对象。我想你应该想到了,WinMain函数每个程序也只能有一个,那么这个全局对象跟WinMain函数肯定有莫大的关系?没错,相信你的直觉。
特别注意:深晓C++细节的人一定知道,全局对象优先于MAIN函数执行的道理。如果你不知道也没关系,那么我在这里告诉你:“全局对象优先于MIAN函数执行,且构建于栈中,切记,切记!”
现在,我们该深入WinMain运行机制了,确切的说,应该是MFC的机制!
首先,看看MFC的库文件把,它能给我们带来许多惊喜。(vc6的相应的目录是\Microsoft Visual Studio\VC98\MFC\SRC;VC7相应的目录是\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\mfc)
现在我们就从这个全局下手,开始今天的旅途。
CMyApp theApp;
此时,系统会执行CMyApp的父类(CWinApp)构造函数,再执行CMyApp的构造函数。(先有老爹,再有儿子!),此时就会调用CWinApp的构造函数。

CWinApp的构造函数(在VC提供的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();
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;
ASSERT(AfxGetApp() == this);
... ...
}
OK,就到这里就可以了,仔细看上面代码,它已经完成了应用程序线程额的启动,它给予了我们程序的生命。现在请注意:
pThreadState->m_pCurrentWinThread = this;
pModuleState->m_pCurrentWinApp = this;
这两行代码其实都是做的一件事儿。
这段代码的意思是,获得了CMyApp的全局对象的this指针。(此时你肯定要疑问,为什么是CMyApp的指针?this目前是在CWinApp中啊? 对此我的答案是,可是你是由CMyApp的对象引发的CWinApp的构造啊!!)这个指针可非一般的人物,稍后我们的很多工作都要靠它完成。
CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置和初始值。
构造完父类,现在构造子类。可是我们看到,AppWizard给我们的子类里它什么也没做?是的,这一切都听从你的安排!
CMyApp::CMyApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}

接下来就是今天的主角儿了,搜索关键字“WinMain”,出现很多文件。别急,因为现在我们应该先看看WinMain的声明。打开appmodul.cpp:

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

这里_tWinMain是为了支持UNICODE而命名的一个宏,真正起作用的是AfxWinMain,注意看看它的参数,是不是和SDK的WinMain函数一样?
现在再搜索下AfxWinMain,其实在winmain.cpp中:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
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();
... ...
}
此段代码注意五个细节:
CWinApp* pApp = AfxGetApp();
意为获得对象指针,其实就是刚才那个THIS。不记得了?指向CMyApp的那个!还值得注意的是,Afx意是全局的,随时你都可以调用它。(AFX就是MFC开发小组的开发代号,意为Application Framework 传说X只是为了好看,没实在意思?!)
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
AfxWinInit完成了线程的初始化和窗框类的注册。具体参看appinit.cpp中的定义。
if (pApp != NULL && !pApp->InitApplication())
其实pApp和pThread是同一个指针,都是指向CMyApp的指针,这里因为CMyApp中没有定义InitApplication,实际上就调用的CWinApp::InitApplication(),完成了MFC的内容管理。
if (!pThread->InitInstance())
因为CMyApp中改写了它,所以调用CMyApp中的,其实它也是初始化工作。此时也完成了默认窗口类的定义。假如你熟悉SDK编程的话,一定不会忘记窗口类的设计、注册、创建、现实及更新的步骤,此时MFC以为你设计好了默认的窗口类。
现在你不禁要疑问,InitApplication()和InitInstance()有何不同?
答案是,假如你执行一个程序,于是两个函数都会被调用;当你在不关闭前一个程序的前提下,再执行一个程序,那么就只执行后一个函数。
nReturnCode = pThread->Run();
这个一步骤在《深入浅出MFC》中被成为程序的活水源头,在我看来它就是你开车踩油门的步骤。待会我们会具体阐述!

在设计窗口类以后,就应该是注册,MFC自动调用(跳转到)AfxEndDeferRegisterClass(WINCORE.CPP中),为你注册了五个窗口类,分别是:AfxWnd,AfxCreateBar,AfxMDIFrame,AfxFrameOrView,AfxOleControl以上窗口类MFC将自动转化成独立无二的类名,供其调用。
在窗口的注册以后,就应该是窗口的创建工作,此时会调用CFrameWnd::Create(),该代码位于WINFRM.Cpp中
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
// load in a menu that will get destroyed when window gets destroyed
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
}

m_strTitle = lpszWindowName; // save title for later

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}

return TRUE;
}

其中完成了窗口的创建工作,里面还涉及扩展风格的调用CreateEx,具体细节请参看MSDN。

此时你不禁要问,我们的事儿都让MFC做完了?工业化生产出来的窗口都是千篇一律啊,我要有我自己的风格!
别急,MFC给用户提供了一个修改窗口设计的机会那就是:PreCreateWindow(CREATESTRUCT& cs) 你在MSDN中查询一下CREATESTRUCT这个结构体,你会发现它和我们的CreateWindow几乎是一模一样,这个就是MFC留给你修改窗口的一个机会。在PreCreateWindow时,会跳到CWnd::PreCreateWindow,里面有一个宏:AfxDeferRegisterClass,它的作用是:如果该窗口类没有被注册,那么就注册它;如果注册了,就什么也不管!
窗口类的设计、注册、创建都已经完成,现在只剩下更新和显示了。这些工作都交由 CMyApp::InitInstance()完成:
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
现在if (!pThread->InitInstance())的工作已经完成,按照MAIN函数的内容,接下来该:nReturnCode = pThread->Run()了
此时应该调用CMyApp的Run()函数,但是在CMyApp类中,根本没有声明或定义这样一个函数,根据多态性的原来,指针迁升,指向CWinApp::Run(),其代码位于APPCORE.CPP中:

int CWinApp::Run()
{
if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
{
// Not launched /Embedding or /Automation, but has no main window!
TRACE(traceAppMsg, 0, "Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n");
AfxPostQuitMessage(0);
}
return CWinThread::Run();
}

最后你会发现,它由调用了一个CWinThread::Run(),此时你就看不到CWinThread::Run()的代码了(至少笔者没有找到,因为微软只提供了部分MFC代码。)但是你可以在MSDN中找到CWinThread::Run()的描述:
Run 控制线程的函数。包含消息泵。一般不重写。
再具体点就是:
Run acquires and dispatches Windows messages until the application receives a WM_QUIT message. If the thread's message queue currently contains no messages, Run calls OnIdle to perform idle-time processing. Incoming messages go to the PreTranslateMessage member function for special processing and then to the Windows function TranslateMessage for standard keyboard translation. Finally, the DispatchMessage Windows function is called.
Run is rarely overridden, but you can override it to implement special behavior.
This member function is used only in user-interface threads.
原来它把消息循环包装了一下,在MFC中称为消息映射(message map)的东西!至于消息映射的具体细节本人会另写文章说明!
OK,MFC不再神秘,掌握了它的来龙去脉,再看其他的MFC书籍的时候,就知道我该怎么做?为什么我要这样做?起到了知其然又知其所以然的效果,这就是我所追求的技术境界
温馨提示:内容为网友见解,仅供参考
第1个回答  2020-11-28
窗口创建机制,消息映射机制,动态创建机制,运行时类信息机制,序列化机制。
第2个回答  2013-07-08
所谓机制就是结构与原理,常见的是消息映射机制……,它的作用是使程序处理消息更方便、直接、紧凑

MFC有哪些机制
MFC六大机制:程序的初始化过程、运行时类型识别、动态创建、永久保存、消息映射和消息传递 参考资料:http:\/\/wenku.baidu.com\/link?url=lDhg0X6oOs2g6X9x0x7jLTdFr_yseEZ0RyqZ5jTGLfdvUHZJ5jQMpV8muLxHeDjlkbW1uFm7hcmXCKjRMKbsXmw4HiGTTwOyacgHEVgb73G ...

mfc 是什么意思?
MFC是Microsoft Foundation Classes,是一组用于开发Windows应用程序的C++类库。它是为了简化开发Windows应用程序而开发的,包含了各种常用的GUI控件,例如按钮、文本框、菜单等。MFC是一个基于消息传递机制的框架,通过这种机制可以更方便地生成事件响应和用户交互过程,尤其是对于需要处理流程控制和数据结构等较...

MFC,UI,GDI的含义
MFC消息机制,UI线程,工作线程,模式对话框原理,非模式对话框原理。MFC中UI线程,GDI绘图包括以下步骤:获取设备环境,设置坐标映射,创建绘图工具,调用DC绘图函数绘图。微软基础类库(英语:MicrosoftFoundationClasses,简称MFC)是微软公司提供的一个类库(classlibraries),以C++类的形式封装了WindowsAPI,...

MFC是什么意思?
MFC通过提供预定义的接口和工具,如AppWizard、资源编辑器和ClassWizard,帮助开发者构建应用程序,特别是通过以文档-视图为中心的编程模式,使得数据操作更加直观和高效。MFC的框架设计包含基础类如CObject和CCmdTarget,它们提供了诸如动态类信息、对象序列化和消息处理等功能。MFC通过消息映射机制,解决了虚拟函...

知道MFC的运行机制有什么用
pMainFrame = new CMainFrame,第一次进入CWinApp::OnFileNew()时完成CDocument派生类的动态创建,CView派生类是在CFrameWnd::OnCreate()中动态创建的。AfxGetApp()函数,是个全局函数,再关于其定义不详细解释,无非就是一直关联到CWinApp类的构造函数中this指针,这个this指针的作用域是CWinApp的构造函数。...

关于MFC 的重画机制 求大神解答 在线等 求救
首先,MFC但文档的工程,系统会带一个这样的 OnDraw(CDC* pDC)你确定你写的OnDraw没有覆盖掉系统的。另外,你可以在OnDrow函数的开头MessageBox或者其他方式输出一下,看Invalidate之后该函数是否被调用到了。如果都调用到了,再检查OnDrow里面的逻辑是否正确的 ...

MFC画面切换以后图像消失怎么办
MFC的机制是窗口被遮挡(最小化)后,恢复视图时。自动产生WM_PAINT消息发送给视图刷新窗口。该消息会依次触发OnPaint()、OnDraw()函数。如果你的绘图语句是放在一个自定义函数中,并且不是在上述2个函数中调用的话(比如在按钮的处理函数中调用),就只能在屏幕上出现一次,窗口一旦更新就消失了。所以...

Windows消息机制《MFC深度详解》
消息映射机制使用消息分派机制,MFC内部实现,通过宏展开显示整个消息映射表,窗口消息只能由CWnd对象处理。命令消息由CCmdTarget对象接收,除直线上溯处理方式外,还支持命令绕行机制。控件通知消息一般由窗口对象处理,可以绕行至其他CCmdTarget对象。非模态对话框消息处理与父窗口不干扰,模态对话框阻塞父窗口,...

MFC已经过时了么?那现在流行什么框架?
windows下MFC没有过时 MFC之所以创造了消息机制是为了实现其Frame\/View\/Doc三位一体的架构。Frame\/View\/Doc架构的意义在于将处理消息的职责分配到合理的类中去处理,例如在菜单上点击一个"保存"选项,处理这个消息就应该交给Doc类来实现,而如果点击"更新"选项,则将这个消息交给View类来处理更方便一些。M...

MFC有哪些机制
现在,我们该深入WinMain运行机制了,确切的说,应该是MFC的机制!首先,看看MFC的库文件把,它能给我们带来许多惊喜。(vc6的相应的目录是\\Microsoft Visual Studio\\VC98\\MFC\\SRC;VC7相应的目录是\\Microsoft Visual Studio .NET 2003\\Vc7\\atlmfc\\src\\mfc)现在我们就从这个全局下手,开始今天的旅途。CMyApp theApp; ...

相似回答