Lesson 03MFC应用程序的生与死.docx
- 文档编号:13369808
- 上传时间:2023-06-13
- 格式:DOCX
- 页数:18
- 大小:68.58KB
Lesson 03MFC应用程序的生与死.docx
《Lesson 03MFC应用程序的生与死.docx》由会员分享,可在线阅读,更多相关《Lesson 03MFC应用程序的生与死.docx(18页珍藏版)》请在冰点文库上搜索。
Lesson03MFC应用程序的生与死
Lesson03MFC应用程序的生与死
一、如何学习MFC
1.使用WindowsAPI开发程序
以rawWindowsAPI开发程序,学习的路径是单纯的,条理分明的,你一定先从程序进入点开始,然后产生窗口类,然后产生窗口,然后取得消息,然后分辨消息,然后决定如何处理消息。
虽然动作繁琐,学习却容易。
图1学习WindowsAPI编程
2.使用MFC编程
(1)开始容易,学习困难,如图2
图2学习MFC编程
以MFC开发程序,一开始很快速,因为开发工具会为你产生一个骨干程序,一般该有的各种界面一应俱全。
但是MFC的学习曲线十分陡峭,程序员从骨干程序出发一直到有能力修改程序代码以符合个人的需要,是一段不易攀登的峭壁。
(2)理解MFC的根本,学习变得容易,如图3
如果我们了解Windows程序的基本运行原理,并了解MFC如何把这些基础动作整合起来,我们就能够使MFC学习曲线的陡峭程度缓和下来。
因此能够迅速接受MFC,进而使用MFC。
一条似远实近的道路!
图3理解MFC的根本
3.熟悉MFC的类层次结构
MSDNMFC最主要的几个类及其继承关系。
二、MFC程序的来龙去脉
MFC程序也是Windwos程序,有且只有一个全局对象theApp,当操作系统将程序加载并激活时,这个全局对象获得配置,其构造函数会先执行,比WinMain更早。
MFC实际上把WinMain内部操作封装在CWinApp中,把WndProc内部操作封装在CFrameWnd中:
●CWinApp代表程序本体
●CFrameWnd代表一个主窗口
(1)CWinApp取代WinMain的地位
MFC中CWinApp的声明:
(文件:
AFXWIN.H)
ClassCWinApp:
publicCWinThread
{
//Attributes
//Startupargs(donotchange)
HINSTANCEm_hInstance;
HINSTANCEm_hPrevInstance;
LPTSTRm_lpCmdLine;
intm_nCmdShow;
……
public:
//Overridables
//hooksforyourinitializationcode
virtualBOOLInitApplication();
……
//overridesforimplementation
virtualBOOLInitInstance();
virtualintExitInstance();//returnappexitcode
virtualintRun();
virtualBOOLOnIdle(LONGlCount);//returnTRUEifmoreidleprocessing
……
};
其中记录主窗口句柄的变量在CWinApp的父类CWinThread中。
(文件:
AFXWIN.H)
classCWinThread:
publicCCmdTarget
{
public:
//Attributes
CWnd*m_pMainWnd;//mainwindow(usuallysameAfxGetApp()->m_pMainWnd)
CWnd*m_pActiveWnd;//activemainwindow(maynotbem_pMainWnd)
BOOLm_bAutoDelete;//enables'deletethis'afterthreadtermination
//onlyvalidwhilerunning
HANDLEm_hThread;//thisthread'sHANDLE
……
//Overridables
//threadinitialization
virtualBOOLInitInstance();
//runningandidleprocessing
virtualintRun();
virtualBOOLPreTranslateMessage(MSG*pMsg);
virtualBOOLPumpMessage();//lowlevelmessagepump
virtualBOOLOnIdle(LONGlCount);//returnTRUEifmoreidleprocessing
……
};
(2)CFrameWnd取代WndProc的地位
CFrameWnd主要掌管窗口,MFC内建了一个MessageMap机制,会把消息自动送到与消息对应的特定函数中去;消息与处理函数之间的对应关系由程序员指定。
下面的宏把消息与其处理函数关联在一起:
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
ON_WM_PAINT()
……
END_MESSAGE_MAP
与DECLARE_MESSAGE_MAP对应
(3)应用程序对象theApp
每个MFC应用程序都有且只有一个应用程序对象:
theApp,当程序运行时,这个全局对象产生,于是其构造函数执行。
CWinApp类的构造函数内容如下:
(文件:
APPCORE.CPP)
CWinApp:
:
CWinApp(LPCTSTRlpszAppName)
{
if(lpszAppName!
=NULL)
m_pszAppName=_tcsdup(lpszAppName);
else
m_pszAppName=NULL;
//initializeCWinThreadstate
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();
//initializeCWinAppstate
ASSERT(afxCurrentWinApp==NULL);//onlyoneCWinAppobjectplease
pModuleState->m_pCurrentWinApp=this;
ASSERT(AfxGetApp()==this);
//innon-runningstateuntilWinMain
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;
//initializewaitcursorstate
m_nWaitCursorCount=0;
m_hcurWaitCursorRestore=NULL;
//initializecurrentprinterstate
m_hDevMode=NULL;
m_hDevNames=NULL;
m_nNumPreviewPages=0;//notspecified(defaultsto1)
//initializeDAOstate
m_lpfnDaoTerm=NULL;//willbesetifAfxDaoInitcalled
//otherinitialization
m_bHelpMode=FALSE;
m_nSafetyPoolSize=512;//defaultsize
}
CWinApp之中的成员变量因为theApp全局对象的产生而获得配置与初值。
(4)隐含的WinMain
theApp配置完成后,WinMain开始,其代码是MFC早已准备好并由链接器直接加到应用程序的代码中,代码如下,_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏:
(文件:
APPMODUL.CPP)
extern"C"intWINAPI
_tWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,intnCmdShow)
{
//callshared/exportedWinMain
returnAfxWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);
}
MFC程序的入口点:
AfxWinMain:
(文件:
WINMAIN.CPP)
//StandardWinMainimplementation
//Canbereplacedaslongas'AfxWinInit'iscalledfirst
intAFXAPIAfxWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,intnCmdShow)
{
ASSERT(hPrevInstance==NULL);
intnReturnCode=-1;
CWinThread*pThread=AfxGetThread();
CWinApp*pApp=AfxGetApp();
//AFXinternalinitialization
if(!
AfxWinInit(hInstance,hPrevInstance,lpCmdLine,nCmdShow))
gotoInitFailure;
//Appglobalinitializations(rare)
if(pApp!
=NULL&&!
pApp->InitApplication())
gotoInitFailure;
//Performspecificinitializations
if(!
pThread->InitInstance())
{
if(pThread->m_pMainWnd!
=NULL)
{
TRACE0("Warning:
Destroyingnon-NULLm_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode=pThread->ExitInstance();
gotoInitFailure;
}
nReturnCode=pThread->Run();
InitFailure:
#ifdef_DEBUG
//CheckformissingAfxLockTempMapcalls
if(AfxGetModuleThreadState()->m_nTempMapLock!
=0)
{
TRACE1("Warning:
Tempmaplockcountnon-zero(%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
returnnReturnCode;
}
(5)AfxWinMain的四个主要操作以及引发的行为:
①AfxWinInit:
内部初始化操作
AfxWinInit是继CWinApp构造函数之后的第一个操作,以下为源代码:
(文件:
APPINIT.CPP)
BOOLAFXAPIAfxWinInit(HINSTANCEhInstance,HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,intnCmdShow)
{
ASSERT(hPrevInstance==NULL);
//handlecriticalerrorsandavoidWindowsmessageboxes
SetErrorMode(SetErrorMode(0)|
SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
//setresourcehandles
AFX_MODULE_STATE*pModuleState=AfxGetModuleState();
pModuleState->m_hCurrentInstanceHandle=hInstance;
pModuleState->m_hCurrentResourceHandle=hInstance;
//fillintheinitialstatefortheapplication
CWinApp*pApp=AfxGetApp();
if(pApp!
=NULL)
{
//Windowsspecificinitialization(notdoneifnoCWinApp)
pApp->m_hInstance=hInstance;
pApp->m_hPrevInstance=hPrevInstance;
pApp->m_lpCmdLine=lpCmdLine;
pApp->m_nCmdShow=nCmdShow;
pApp->SetCurrentHandles();
}
//initializethreadspecificdata(formainthread)
if(!
afxContextIsDLL)
AfxInitThread();
returnTRUE;
}
②CWinApp:
:
InitApplication
AfxWinInit之后的操作是pApp->InitApplication。
实际的pApp指向CMyWinApp的对象,也就是theApp,CMyWinApp的父类是CWinApp,而InitApplication是CWinApp的一个虚函数,在CMyWinApp中没有重写它(大多数情况不需要重写它),因而最终实质调用的是:
CWinApp:
:
InitApplication();
此函数的程序原代码:
(文件:
APPCORE.CPP)
BOOLCWinApp:
:
InitApplication()
{
if(CDocManager:
:
pStaticDocManager!
=NULL)
{
if(m_pDocManager==NULL)
m_pDocManager=CDocManager:
:
pStaticDocManager;
CDocManager:
:
pStaticDocManager=NULL;
}
if(m_pDocManager!
=NULL)
m_pDocManager->AddDocTemplate(NULL);
else
CDocManager:
:
bStaticInit=FALSE;
returnTRUE;
}
这些操作都是MFC的内部管理
③CMyWinApp:
:
InitInstance
InitApplication之后,AfxWinMain调用了pThread->InitInstance(),CWinApp的父类是CWinThread,CWinApp是CMyWinApp的父类,而CMyWinApp实现了虚拟函数InitInstance(),所以实际调用的是CMyWinApp:
:
InitInstance()。
●CFrameWnd:
:
Create产生主窗口(并先注册窗口类)
CMyWinApp:
:
InitInstance()会引发CMyFrameWnd构造函数的调用(New了窗口对象),接着会执行LoadFrame(),再执行Create()函数,从而产生窗口,在产生窗口之前,会引发窗口类的注册操作。
(实际还有很多动作执行,由MFC内部机制完成)
CFrameWnd:
:
Create(winfrm.cpp)->CreateEx(wincore.cpp)->PreCreateWindow(winfrm.cpp)
->AfxDeferRegisterClass(AFXIMPL.H,宏)
->AfxEndDeferRegisterClass(wincore.cpp)->DefWindowProc
->AfxRegisterClass->RegisterClass或
->RegisterWithIcon->AfxRegisterClass->RegisterClass
->CreateWindowEx
●窗口的显示与更新
CMyFrameWnd:
:
CMyFrameWnd结束之后,窗口已经产生,又回到CMyWinApp:
:
InitInstance(),于是调用ShowWindow和UpdateWindow显示和更新窗口。
④CWinThread:
:
Run()
接下来调用Run(),在CWinApp:
:
Run()中(文件:
APPCORE.CPP),最后是调用CWinThread:
:
Run(),(文件:
THRDCORE.CPP)
intCWinThread:
:
Run()
{
ASSERT_VALID(this);
//fortrackingtheidletimestate
BOOLbIdle=TRUE;
LONGlIdleCount=0;
//acquireanddispatchmessagesuntilaWM_QUITmessageisreceived.
for(;;)
{
//phase1:
checktoseeifwecandoidlework
while(bIdle&&
!
:
:
PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE))
{
//callOnIdlewhileinbIdlestate
if(!
OnIdle(lIdleCount++))
bIdle=FALSE;//assume"noidle"state
}
//phase2:
pumpmessageswhileavailable
do
{
//pumpmessage,butquitonWM_QUIT
if(!
PumpMessage())
returnExitInstance();
//reset"noidle"stateafterpumping"normal"message
if(IsIdleMessage(&m_msgCur))
{
bIdle=TRUE;
lIdleCount=0;
}
}while(:
:
PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE));
}
ASSERT(FALSE);//notreachable
}
……
BOOLCWinThread:
:
PumpMessage()
{
ASSERT_VALID(this);
if(!
:
:
GetMessage(&m_msgCur,NULL,NULL,NULL))
{
#ifdef_DEBUG
if(afxTraceFlags&traceAppMsg)
TRACE0("CWinThread:
:
PumpMessage-ReceivedWM_QUIT.\n");
m_nDisablePumpCount++;//applicationmustdie
//Note:
preventscallingmessageloopthingsin'ExitInstance'
//willneverbedecremented
#endif
returnFALSE;
}
#ifdef_DEBUG
if(m_nDisablePumpCount!
=0)
{
TRACE0("Error:
CWinThread:
:
PumpMessagecalledwhennotpermitted.\n");
ASSERT(FALSE);
}
#endif
#ifdef_DEBUG
if(afxTraceFlags&traceAppMsg)
_AfxTraceMsg(_T("PumpMessage"),&m_msgCur);
#endif
//processthismessage
if(m_msgCur.message!
=WM_KICKIDLE&&!
PreTranslateMessage(&m_msgCur))
{
:
:
TranslateMessage(&m_msgCur);
:
:
DispatchMessage(&m_msgCur);
}
returnTRUE;
}
注意:
上面消息循环,MFC采用消息映射机制(MessageMap):
窗口函数由MFC提供,采用消息映射宏把消息与处理函数相联系。
MFC把消息主要分为三类,MessageMap机制中对于消息与函数之间的对应关系也基本为三种:
1标准Windows消息(WM_XXX)的对应规则:
宏名称
对应消息
消息处理函数
(名称已由系统默认)
ON_WM_CHAR
WM_CHAR
OnChar
ON_WM_CLOSE
WM_CLOSE
OnClose
ON_WM_CREATE
WM_CREATE
OnCreate
ON_WM_DESTROY
WM_DESTROY
OnDestroy
ON_WM_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Lesson 03MFC应用程序的生与死 03 MFC 应用程序