MFC框架原理以及消息运行机制Word文件下载.docx
《MFC框架原理以及消息运行机制Word文件下载.docx》由会员分享,可在线阅读,更多相关《MFC框架原理以及消息运行机制Word文件下载.docx(22页珍藏版)》请在冰豆网上搜索。
![MFC框架原理以及消息运行机制Word文件下载.docx](https://file1.bdocx.com/fileroot1/2022-11/30/c43461c5-15d0-441d-b491-3d3d21bec7cf/c43461c5-15d0-441d-b491-3d3d21bec7cf1.gif)
LPSTRlpCmdLine,//命令行指针
intnCmdShow//(窗口)显示的状态
);
说明:
WinMain函数是Windows程序入口点函数,由OS调用,当OS启动应用程序的时候,winmain函数的参数由OS传递的。
6,创建一个完整的窗口需要经过下面四个操作步骤:
一,设计一个窗口类;
如:
WNDCLASSwndcls;
二,注册窗口类;
如:
RegisterClass(&
wndcls);
三,创建窗口;
CreateWindow(),CreateWindowEX();
四,显示及更新窗口。
ShowWindow(),UpdateWindow();
创建窗口的时候一定要基于已经注册的窗口类.
7,Windows提供的窗口类:
typedefstruct_WNDCLASS{
UINTstyle;
//窗口的类型
WNDPROClpfnWndProc;
//窗口过程函数指针(回调函数)
intcbClsExtra;
//窗口类附加字节,为该类窗口所共享。
通常0。
intcbWndExtra;
//窗口附加字节。
通常设为0。
HANDLEhInstance;
//当前应用程序事例句柄。
HICONhIcon;
//图标句柄LoadIcon();
HCURSORhCursor;
//光标句柄LoadCursor();
HBRUSHhbrBackground;
//画刷句柄(HBRUSH)GetStockObject();
LPCTSTRlpszMenuName;
//菜单名字
LPCTSTRlpszClassName;
//类的名字
}WNDCLASS;
8,窗口类注册:
ATOMRegisterClass(
CONSTWNDCLASS*lpWndClass//addressofstructurewithclass
//data
9,创建窗口:
HWNDCreateWindow(
LPCTSTRlpClassName,//pointertoregisteredclassname
LPCTSTRlpWindowName,//pointertowindowname
DWORDdwStyle,//windowstyle
intx,//horizontalpositionofwindow
inty,//verticalpositionofwindow
intnWidth,//windowwidth
intnHeight,//windowheight
HWNDhWndParent,//handletoparentorownerwindow
HMENUhMenu,//handletomenuorchild-windowidentifier
HANDLEhInstance,//handletoapplicationinstance
LPVOIDlpParam//pointertowindow-creationdata
10,显示和更新窗口窗口:
BOOLShowWindow(
HWNDhWnd,//handletowindow
intnCmdShow//showstateofwindow
BOOLUpdateWindow(
HWNDhWnd//handleofwindow
11,消息循环:
MSGmsg;
while(GetMessage(&
msg,...))//从消息队列中取出一条消息
{
TranslateMessage(&
msg);
//进行消息(如键盘消息)转换
DispatchMessage(&
//分派消息到窗口的回调函数处理,(OS调用窗口回调函数进行处理)。
}
其中:
//**TheGetMessagefunctionretrievesamessagefromthecallingthread'
smessagequeueandplacesitinthespecifiedstructure.
//**IfthefunctionretrievesamessageotherthanWM_QUIT,thereturnvalueisnonzero.IfthefunctionretrievestheWM_QUITmessage,thereturnvalueiszero.Ifthereisanerror,thereturnvalueis-1.
BOOLGetMessage(
LPMSGlpMsg,//addressofstructurewithmessage
HWNDhWnd,//handleofwindow
UINTwMsgFilterMin,//firstmessage
UINTwMsgFilterMax//lastmessage
//TheTranslateMessagefunctiontranslatesvirtual-keymessagesintocharactermessages.Thecharactermessagesarepostedtothecallingthread'
smessagequeue,tobereadthenexttimethethreadcallstheGetMessageorPeekMessagefunction.
BOOLTranslateMessage(
CONSTMSG*lpMsg//addressofstructurewithmessage
//TheDispatchMessagefunctiondispatchesamessagetoawindowprocedure.
LONGDispatchMessage(
CONSTMSG*lpmsg//pointertostructurewithmessage
12,窗口过程函数(回调函数)原型:
TheWindowProcfunctionisanapplication-definedfunctionthatprocessesmessagessenttoawindow.TheWNDPROCtypedefinesapointertothiscallbackfunction.WindowProcisaplaceholder(占位符)fortheapplication-definedfunctionname.
LRESULTCALLBACKWindowProc(//这里WindowProc是个代号名字。
HWNDhwnd,//handletowindow
UINTuMsg,//messageidentifier
WPARAMwParam,//firstmessageparameter
LPARAMlParam//secondmessageparameter
两种函数调用约定(__stdcall和__cdecl):
#defineCALLBACK__stdcall
//__stdcall标准调用预定,是PASCAL调用约定,象DELPHI使用的就是标准调用约定
#defineWINAPIV__cdecl
//__cdecl是C语言形式的调用约定。
主要区别:
函数参数传递顺序和对堆栈的清除上。
问题:
除了那些可变参数的函数调用外,其余的一般都是__stdcall约定。
但C/C++编译默然的是__cdecl约定。
所以如果在VC等环境中调用__stdcall约定的函数,必须要在函数声明的时加上__stdcall修饰符,以便对这个函数的调用是使用__stdcall约定(如使用DELPHI编写的DLL时候)。
(VC中可通过这途径修改:
project|settings..|c/c++|...)
在窗口过程函数中通过一组switch语句来对消息进行处理:
LRESULTCALLBACKWindowProc(
HWNDhwnd,
UINTuMsg,
WPARAMwParam,
LPARAMlParam
)
switch(uMsg)
caseWM_PAINT:
...
break;
case...
caseWM_CLOSE:
//DestroyWindow(hwnd);
//销毁窗口,并发送WM_DESTROY消息。
caseWM_DESTROY:
//PostQuitMessage(0);
//发送WM_QUIT消息到消息队列中,请求终止。
//GetMessage()取到WM_QUIT消息后,返回0,退出消息循//环,从而终止应用程序。
default:
returnDefWindowProc(hwnd,uMsg,wParam,lParam);
//用缺省的窗口过程处理我们不感兴趣的消息(其它消息)。
//这是必须的。
}//switch
return0;
}//WindowProc
13,DestroyWindow()函数和PostQuitMessage()函数原型:
//**TheDestroyWindowfunctiondestroysthespecifiedwindow.ThefunctionsendsWM_DESTROYandWM_NCDESTROYmessages。
BOOLDestroyWindow(
HWNDhWnd//handletowindowtodestroy
//**ThePostQuitMessagefunctionindicatestothesystemthatathreadhasmadearequesttoterminate(quit).ItistypicallyusedinresponsetoaWM_DESTROYmessage.
//**ThePostQuitMessagefunctionpostsaWM_QUITmessagetothethread'
smessagequeueandreturnsimmediately;
thefunctionsimplyindicates(预示,通知)tothesystemthatthethreadisrequestingtoquitatsometimeinthefuture.
WhenthethreadretrievestheWM_QUITmessagefromitsmessagequeue,itshouldexititsmessageloopandreturncontroltothesystem.
VOIDPostQuitMessage(
intnExitCode//exitcode
14,关于DC句柄获取:
a)使用BeginPaint(),EndPaint()对。
注意只能在响应WM_PAINT消息时使用。
b)使用GetDc(),ReleaseDC()对。
注意他们不能在响应WM_PAINT中使用。
(2)C++
1,c语言中,结构体struct中不能包括函数的,而在C++中struct中可以包括函数。
2,C++中结构体和类可以通用,区别主要表现在访问控制方面:
struct中默认是public,而class中默认的是private。
3,构造函数最重要的作用是创建对象的本身,C++中每个类可以拥有多个构造函数,但必须至少有一个构造函数,当一个类中没有显式提供任何构造函数,C++编辑器自动提供一个默认的不带参数的构造函数,这个默认的构造函数只负责构造对象,不做任何初始化工作。
但在一个类中只要自己定义一个构造函数,不管带参不带参,编辑器不再提供默认的不带参的构造函数了。
构造函数没有返回值。
4,析构函数当一个对象生命周期结束时候被调用来回收对象占用的内存空间。
一个类只需有一个析构函数。
析构函数没有返回值也不的带参数。
5,析构函数的作用与构造函数相反,对象超出起作用范围对应的内存空间被系统收回,或被程序用delete删除的时候,对象的析构函数被调用。
6,函数的重载条件:
函数的参数类型、个数不同,才能构成函数的重载。
重载是发生在同一个类中。
7,类是抽象的,不占用具体物理内存,只有对象是实例化的,是占用具体物理内存的。
8,this指针是隐含指针,指向对象本身(this指针不是指向类的),代表了对象的地址。
所有的对象调用的成员函数都是同一代码段,但每个对象都有自己的数据成员。
当对象通过调用它的成员函数来访问它的数据成员的时候,成员函数除了接收实参外,还接收了对象的地址,这个地址被一个隐藏的形参this所获取,通过这个this指针可以访问对象的数据成员和成员函数。
9,对象中public属性的成员在外部和子类中都可以被访问;
protected属性的成员在外部不能被访问,在子类中是可以访问的;
private属性在子类中和外部都不能被访问。
10,类的继承访问特性:
(public,protected,private)
a)基类中private属性成员,子类无论采用那种继承方式都不能访问。
b)采用public继承,基类中的public,protected属性的成员访问特性在子类中仍然保持一致。
c)采用protected继承,基类中的public,protected属性成员访问特性在子类中变为protected.
d)采用private继承,基类中的public,protected属性成员访问特性在子类中变为private.
11,子类和基类的构造函数或析构函数调用顺序:
当调用子类的构造函数时候先调用基类的构造函数(如果没有指明,则调用基类却省那个不带参数的构造函数;
如果要指明则在子类构造函数名后加"
:
基类名(参数)"
)。
析构函数则相反,先调用子类析构函数,后调用基类的析构函数。
12,函数的覆盖:
函数的覆盖是发生在发生父类和子类之间的。
(函数的重载是发生在同一个类中)
当子类中重写了父类的某些成员函数后,子类中的成员函数覆盖了父类的对应同名成员函数。
13,用父类指针访问子类对象成员时候,只能访问子类从父类继承来的那部分。
(这时候外部不可以访问父类中保护和私有的部分,子类中不可访问父类私有部分。
14,多态性:
在基类的的成员函数前加virturl变成虚函数,当用子类对象调用该功能的成员函数时候,子类有的就调用子类的,子类没有的就调用基类的。
当C++编译器在编译的时候,发现被调用的成员函数在基类中定义的是虚函数,这个时候C++就会采用迟绑定技术(latebinding),在运行的时候,依据对象的类型来确定调用的哪个函数,子类有调用子类的,子类没有的就调用基类的。
如果基类中的成员函数不是虚函数,则这时候的绑定是早期绑定,在编译的时候就已经确定该调用哪个函数。
15,纯虚函数:
在类中定义时eg:
virtualvoidfunc1()=0;
纯虚函数没有函数体,含有纯虚函数的类叫做抽象类,抽象类不能实例化对象。
当子类从抽象类的基类中派生出来时候,如果没有实现基类中的纯虚函数,则子类也是个抽象类,也不能实例化对象。
纯虚函数被标名为不具体实现的虚成员函数,纯虚函数可以让类只具有操作的名称而不具有具体的操作的内容,让派生类在继承的时候再给出具体的定义。
如果派生类没有给出基类的纯虚函数的具体定义的时候,派生类也为一个抽象类,也不能实例化对象。
16,引用:
变量的别名。
引用需要在定义的时候用一变量或对象初始化自己。
引用一旦在定义的时候初始化,就维系在一个特定的变量或对象上。
引用不占用物理内存(与定义引用的目标共用同一内存)。
指针变量需要占用物理内存,用来存储地址。
(3)MFC程序框架的剖析
1,寻找WinMain人口:
在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码。
路径:
MFC|SRC|APPMODUL.CPP:
_tWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,intnCmdShow)
//callshared/exportedWinMain
returnAfxWinMain(hInstance,hPrevInstance,lpCmdLine,
nCmdShow);
注意:
(#define_tWinMainWinMain)
2,对于全局对象或全局变量来说,在程序运行即WINMAIN函数加载的时候,已经为全局对象或全局变量分配了内存和赋初值。
所以:
CTEApptheApp;
->
CTEApp:
CTEApp(){}->
_tWinMain(){}
每一个MFC程序,有且只有一个从WinApp类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身。
在WIN32程序当中,表示应用程序是通过WINMAIN入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。
在基于MFC应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。
3,通过构造应用程序对象过程中调用基类CWinApp的构造函数,在CWinApp的构造函数中对程序包括运行时一些初始化工作完成了。
CWinApp构造函数:
MFC|SRC|APPCORE.CPP
CWinApp:
CWinApp(LPCTSTR
lpszAppName){...}//带参数,而CTEApp构造函数没有显式向父类传参,难道CWinApp()有默认参数?
见下:
(在CWinApp类定义中,CWinApp(LPCTSTRlpszAppName=NULL);
)
CWinApp()函数中:
pThreadState->
m_pCurrentWinThread=this;
pModuleState->
m_pCurrentWinApp=this
(this指向的是派生类CTEApp对象,即theApp)
调试:
CWinApp();
(->
CTEApp
CTEApp())->
CWinApp()->
CTEApp()->
4,_tWinMain函数中通过调用AfxWinMain()函数来完成它要完成的功能。
(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。
AfxWinMain()函数路径:
MFC|SRC|WINMAIN.CPP:
在AfxWinMain()函数中:
CWinApp*pApp=AfxGetApp();
pApp存储的是指向WinApp派生类对象(theApp)的指针。
//_AFXWIN_INLINECWinApp*AFXAPIAfxGetApp()
//{returnafxCurrentWinApp;
}
调用pThread->
InitInstance()
pThread也指向theApp,由于基类中virtualBOOL
InitApplication()定义为虚函数,所以调用pThread->
InitInstance()时候,调用的是派生类CTEApp的InitInstance()函数。
nReturnCode=pThread->
Run();
pThread->
Run()完成了消息循环。
5,注册窗口类:
AfxEndDeferRegisterClass();
AfxEndDeferRegisterClass()函数所在文件:
BOOLAFXAPIAfxEndDeferRegisterClass(LONGfToRegister){...}
设计窗口类:
在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。
_tWinMain(){}//进入程序
AfxWinMain();
pApp->
InitApplication();
InitInstance()//父类InitInstance虚函数;
CTEApp:
InitInstance()//子类实现函数;
AfxEndDeferRegisterClass(LONG
fToRegister)//注册所选择的窗口类(出于文档管理,注册提前,正常的应在PreCreateWindow中进行注册)//之后进入创建