孙鑫VC学习笔记:第三讲 MFC应用程序框架
1.在MFC的源代码中查找入口函数WinMain().
X:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC
APPMODUL.CPP文件中
------------------------------------------------------------------------
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{ //Breakpoint1
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
-------------------------------------------------------------------------
TCHAR.H
------------------------------------------------------------------------
#define _tWinMain WinMain
------------------------------------------------------------------------
Test.cpp
------------------------------------------------------------------------
CTestApp::CTestApp()
{ //Breakpoint2
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
------------------------------------------------------------------------
RUNNING: Breakpoint2->Breakpoint1
首先进入CTestApp的构造函数,然后才到达_tWinMain()函数
Test.cpp
--------------------------------------------------------------------------
CTestApp theApp; //全局对象 //Breakpoint3
--------------------------------------------------------------------------
RUNNING: Breakpoint3->Breakpoint2->Breakpoint1
2.在MFC程序中,通过产生一个应用程序类的对象来表示应用程序本身
在X:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC搜索WinApp
得到:
APPCORE.CPP
--------------------------------------------------------------------------
CWinApp::CWinApp(LPCTSTR lpszAppName) //CWinApp的构造函数
{
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; //this指针指向CTestApp对象(theApp)
//根据继承性的原理(使用程序测试)
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_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的构造函数带有参数LPCTSTR lpszAppName,而CTestApp的构造函数不带有任何参数.
在AFXWIN.H文件中
-----------------------------------------------------------------------------
class CWinApp : public CWinThread
{
DECLARE_DYNAMIC(CWinApp)
public:
// Constructor
CWinApp(LPCTSTR lpszAppName = NULL); //CWinApp的构造函数有缺省的参数
..............................
}
------------------------------------------------------------------------------
3. 回到_tWinMain(...)函数
查找AfxWinMain()函数,Afx表示应用程序框架类函数,相当于全局函数
-------------------------------------------------------------------------------
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread(); //线程的指针,也是指向子类
CWinApp* pApp = AfxGetApp(); //获得指针,这里pApp指向派生类的指针(theApp)
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())//pApp->InitApplication()MFC内部
//管理的函数
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance()) //pThread->InitInstance() //Breakpoint4
//在AFXWIN.H中
//virtual BOOL InitInstance();
//InitInstance是一个虚函数
//此时调用的InitInstance函数是
//CTestApp::InitInstance()
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd/n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();//Run()方法完成我们的消息循环
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld)./n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
------------------------------------------------------------------------------------
4.在CTestApp的InitInstance()函数设置断点
------------------------------------------------------------------------------------
BOOL CTestApp::InitInstance()
{ //Breakpoint5
AfxEnableControlContainer();
.............
}
-------------------------------------------------------------------------------------
RUNNING:<1> 定义全局对象 CTestApp theApp; (Breakpoint3)
<2> 构造全局对象 CTestApp::CTestApp()(Breakpoint2)
<3> 构造基类对象
<4> 进入_tWinMain函数 (Breakpoint1)
<5> 到达AfxWinMain函数
if (!pThread->InitInstance()) (Breakpoint4)
<6> 到达CTestApp::InitInstance() (Breakpoint5)
5.注册窗口类
AfxEndDeferRegisterClass函数
WINCORE.CPP中 (注册窗口类应该在PreCreateWindow中调用)
由于是单文档应用程序的原因,事先调用AfxEndDeferRegisterClass函数注册窗口
-------------------------------------------------------------------------------------
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{ // Breakpoint6
// mask off all classes that are already registered
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
fToRegister &= ~pModuleState->m_fRegisteredClasses;
if (fToRegister == 0)
return TRUE;
LONG fRegisteredClasses = 0;
........................
wndcls.lpfnWndProc = DefWindowProc;
}
-------------------------------------------------------------------------------------
BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
{
WNDCLASS wndcls;
if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
&wndcls)) //判断窗口是否注册
{
// class already registered
return TRUE;
}
if (!::RegisterClass(lpWndClass)) //调用RegisterClass,API函数
{
TRACE1("Can't register window class named %s/n",
lpWndClass->lpszClassName);
return FALSE;
}
.................................................
}
-------------------------------------------------------------------------------------
<7> 注册窗口类
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister) (Breakpoint6)
6.产生窗口
CMainFrm.CPP
-------------------------------------------------------------------------------------
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{ (Breakpoint7)
if( !CFrameWnd::PreCreateWindow(cs) ) //函数调用
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
-------------------------------------------------------------------------------------
<8>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) (Breakpoint7)
WINFRM.CPP
-------------------------------------------------------------------------------------
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{ (Breakpoint8)
if (cs.lpszClass == NULL)
{
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
//AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)判断当前的窗口类有没有
//注册,没有就注册
cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background
}
if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
cs.style |= FWS_PREFIXTITLE;
if (afxData.bWin4)
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;
}
-------------------------------------------------------------------------------------
AFXIMPL.h
-------------------------------------------------------------------------------------
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
-------------------------------------------------------------------------------------
<9> BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) (Breakpoint8)
WINCORE.cpp
-------------------------------------------------------------------------------------
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{ (Breakpoint9)
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
..............................
if (!PreCreateWindow(cs)) //PreCreateWindow是一个虚函数
{
PostNcDestroy();
return FALSE;
}
...............................
}
-------------------------------------------------------------------------------------
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */) //调用上面的CreateEx函数
{ (Breakpoint10)
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}
-------------------------------------------------------------------------------------
WINFRM.CPP
-------------------------------------------------------------------------------------
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{ (Breakpoint11)
..........................
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) //调用上面的
{ //CreateEx函数
TRACE0("Warning: failed to create CFrameWnd./n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
....................................................
}
-----------------------------------------------------------------------------------
7.显示更新窗口
Test.CPP
-----------------------------------------------------------------------------------
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow(); //m_pMainWnd指向框架窗口对象的指针
-----------------------------------------------------------------------------------
8.消息循环
THRDCORE.CPP
-----------------------------------------------------------------------------------
int CWinThread::Run()
{
ASSERT_VALID(this);
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
}
// phase2: pump messages while available
do
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); // not reachable
}
------------------------------------------------------------------------------------
BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
{
#ifdef _DEBUG
if (afxTraceFlags & traceAppMsg)
TRACE0("CWinThread::PumpMessage - Received WM_QUIT./n");
m_nDisablePumpCount++; // application must die
// Note: prevents calling message loop things in 'ExitInstance'
// will never be decremented
#endif
return FALSE;
}
#ifdef _DEBUG
if (m_nDisablePumpCount != 0)
{
TRACE0("Error: CWinThread::PumpMessage called when not permitted./n");
ASSERT(FALSE);
}
#endif
#ifdef _DEBUG
if (afxTraceFlags & traceAppMsg)
_AfxTraceMsg(_T("PumpMessage"), &m_msgCur);
#endif
// process this message
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);
::DispatchMessage(&m_msgCur);
}
return TRUE;
}
----------------------------------------------------------------------------------
9.窗口过程 (在AfxEndDeferRegisterClass函数中设置)
wndcls.lpfnWndProc = DefWindowProc; //缺省的窗口过程
10.在MFC如何整合CMainFrm类,CTestView类,CTestDoc类?
在
BOOL CTestApp::InitInstance()中:
------------------------------------------------------------------------------------
CSingleDocTemplate* pDocTemplate; //定义一个单文档的类模板
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDoc), //通过单文档的模板组合在一起
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate); //增加到文档模板中
-------------------------------------------------------------------------------------
11.窗口与C++类的关系
窗口销毁,C++的对象不一定销毁,窗口与C++窗口类的关系只不过是窗口类保存了窗口的句柄.
12.CButton
m_btn.Create("维新",WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,
CRect(0,0,100,100),/*GetParent(),*/this,123);
CButton的窗口风格 WS_CHILD | WS_VISIBLE | BS_AUTO3STATE
CTestView的父窗口是CMainFrm,在CTestView里面使用GetParent()函数,得到CMainFrm对象的
指针.
孙鑫VC学习笔记:第三讲 MFC应用程序框架相关推荐
- 孙鑫VC++学习笔记(转载至程序员之家--虎非龙)[11--15] .
第11课 1.创建4个菜单,为其添加消息响应,用成员变量保存绘画类型.添加LButtonDown和Up消息. 2.当窗口重绘时,如果想再显示原先画的数据,则需要保存数据.为此创建一个新类来记录绘画类型 ...
- 孙鑫VC++学习笔记(转载至程序员之家--虎非龙)[11--15]
第11课 1.创建4个菜单,为其添加消息响应,用成员变量保存绘画类型.添加LButtonDown和Up消息. 2.当窗口重绘时,如果想再显示原先画的数据,则需要保存数据.为此创建一个新类来记录绘画类型 ...
- 孙鑫VC学习笔记:第七讲
七.对话框 2006年8月5日 14:25 因为笔记是用OneNote做的,上传以后为看不到图片,于是我截图放到相册上面, 相册地址为:http://photo.163.com/photos/good ...
- mfc编程 孙鑫_孙鑫VC++视频教程笔记-(3)MFC程序框架的剖析 附1-SDI程序流程图
1,寻找WinMain人口: 在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码. 路径:MFC|SRC|APPMODUL.CPP: _tWinMain(HINSTANCE hIns ...
- 孙鑫VC学习系列教程
教程简介 1.循序渐进 从Win32SDK编程开始讲解,帮助大家理解掌握Windows编程的核心 -- 消息循环机制. 2.通俗易懂 编程语言枯燥难懂,然而通过孙鑫老师形象化的讲解,Windows和M ...
- 孙鑫VC++讲座笔记-(6)菜单编程
1,弹出菜单(Pop-up)是不能用来作命令响应的. 2,MFC中菜单项消息如果利用ClassWizard来对菜单项消息分别在上述四个类中进行响应,则菜单消息传递顺序:View类--Doc类--CMa ...
- 孙鑫VC++深入详解第三章学习笔记
第三章 3.1创建MFC AppWizard 如何利用vs2019创建MFC应用见参考文献[1] 需要注意的地方有 [1] 创建MFC单文档应用程序 [2]开启类视图窗口 3.2基于MFC的程序框架剖 ...
- 孙鑫VC++深入详解第二章学习笔记
第二章 掌握C++ 2.1 从结构到类 2.1.1 结构体的定义 C++相比于C的特性:封装性.继承性.多态性: 对象具有状态和行为,状态保存在成员变量中,行为通过函数实现: 标准输入输出流对象:ci ...
- 孙鑫VC++深入详解第一章学习笔记
第一章 Windows程序内部运行机制 1.1 API和SDK API:Windows操作系统提供给应用程序编程的接口. SDK(软件开发包):用于开发的所有资源的集合. 1.2 窗口和句柄 窗口 句 ...
- VC学习笔记:简单绘图
VC学习笔记:简单绘图 SkySeraph Oct.29th 2009 HQU Email-zgzhaobo@gmail.com QQ-452728574 Latest Modified Date ...
最新文章
- Spring5源码 - 11 Spring事件监听机制_源码篇
- mysql 5.7 速度很快_MySQL5.7速度比MySQL5.6快3倍
- [Servlet]研究ServletContext对象
- 国内首家,腾讯云云开发“全家桶”来了
- ROS与Android的通信
- NTT通信公司在大阪开通运营容灾数据中心
- win7如何安装mysql5.7_Win7下安装MySQL5.7.16过程记录
- JavaWeb项目实战一(Servlet+Jsp项目项目搭建及登录界面)
- 中兴威武3android驱动,中兴威武3
- 信息系统管理——项目立项管理(详细可行性研究的结构)
- 程序人生 | 文艺程序员使用代码发展诗歌
- 解决Android手机开发者选项经常自动关闭的问题
- 中英文切换_值得收藏|不重装软件实现ArcGIS中英文版本之间切换
- 吐血整理公众号推文制作技巧
- 趋势跟踪系统的形成历程
- 2020上半年数据分析人才及CDA持证人行业报告
- IOS 调用第三方地图APP导航
- 年终思路梳理(三)——工业互联网
- 机器学习中的置信区间与置信度
- 什么是堆、栈?堆和栈的区别
热门文章
- 中小企业应该将云存储用于主数据吗?
- 《Android程序设计》一3.8 Android应用打包:.apk文件
- Pywinauto在Windows Twain Driver自动化测试中的应用研究
- 经典中的博弈:第一章 C++的Hello,World!
- Android学习笔记--项目框架介绍
- Wordle是优秀的信息可视化吗?如何真正使用Wordle?
- .NET应用服务器(中间件)来到
- c++ string字符串翻转
- Kafka+Spark Streaming+Redis实时系统实践
- 解决Android 4.0以上版本中OptionsMenu菜单不显示ICON图标的问题