Windows消息运行原理 孙鑫讲座笔记学习.docx
《Windows消息运行原理 孙鑫讲座笔记学习.docx》由会员分享,可在线阅读,更多相关《Windows消息运行原理 孙鑫讲座笔记学习.docx(23页珍藏版)》请在冰豆网上搜索。
Windows消息运行原理孙鑫讲座笔记学习
Windows消息运行原理孙鑫讲座笔记学习
(1)Windows程序内部运行机制
1,windows程序设计是种事件驱动方式的程序设计,主要基于消息的。
当用户需要完成某种功能时,需要调用OS某种支持,然后OS将用户的需要包装成消息,并投入到消息队列中,最后应用程序从消息队列中取走消息并进行响应。
2,消息结构:
typedefstructtagMSG{ //msg
HWND hwnd; //接收消息的窗口句柄。
和哪个窗口相关联。
UINT message; //消息标识。
消息本身是什么。
WPARAMwParam; //消息的附加信息。
具体取决于消息本身。
LPARAMlParam;
DWORD time; //消息投递时间。
POINT pt; //消息投递时,光标在屏幕上的位置。
}MSG;
3,消息队列:
每个应用程序OS都为它建立一个消息队列,消息队列是个先进先出的缓冲区,其中每个元素都是一个消息,OS将生成的每个消息按先后顺序放进消息队列中,应用程序总是取走当前消息队列中的第一条消息,应用程序取走消息后便知道用户的操作和程序的状态,然后对其处理即消息响应,消息响应通过编码实现。
4,使用VC编程除了良好的C基础外还需要掌握两方面:
一,消息本身。
不同消息所代表的用户操作和应用程序的状态。
二,对于某个特定的消息来说,要让OS执行某个特定的功能去响应消息。
5,Window程序入口:
intWINAPIWinMain(
HINSTANCEhInstance, //当前事例句柄。
HINSTANCEhPrevInstance, //先前事例句柄。
LPSTRlpCmdLine, //命令行指针
intnCmdShow //(窗口)显示的状态
);
说明:
WinMain函数是Windows程序入口点函数,由OS调用,当OS启动应用程序的时候,winmain函数的参数由OS传递的。
6,创建一个完整的窗口需要经过下面四个操作步骤:
一,设计一个窗口类;如:
WNDCLASSwndcls;
二,注册窗口类; 如:
RegisterClass(&wndcls);
三,创建窗口; 如:
CreateWindow(),CreateWindowEX();
四,显示及更新窗口。
如:
ShowWindow(),UpdateWindow();
说明:
创建窗口的时候一定要基于已经注册的窗口类.
7,Windows提供的窗口类:
typedefstruct_WNDCLASS{
UINT style; //窗口的类型
WNDPROClpfnWndProc; //窗口过程函数指针(回调函数)
int cbClsExtra;//窗口类附加字节,为该类窗口所共享。
通常0。
int cbWndExtra;//窗口附加字节。
通常设为0。
HANDLE hInstance; //当前应用程序事例句柄。
HICON hIcon; //图标句柄LoadIcon();
HCURSORhCursor; //光标句柄LoadCursor();
HBRUSH hbrBackground;//画刷句柄(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(&msg);//分派消息到窗口的回调函数处理,(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...
break;
caseWM_CLOSE:
//DestroyWindow(hwnd);
//销毁窗口,并发送WM_DESTROY消息。
break;
caseWM_DESTROY:
//PostQuitMessage(0);
//发送WM_QUIT消息到消息队列中,请求终止。
//GetMessage()取到WM_QUIT消息后,返回0,退出消息循 // 环,从而终止应用程序。
break;
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++编辑器自动提供一个默认的不带参数的构造函数,这个默认的构造函数只负责构造对象,不做任何初始化工作5谝桓隼嘀兄灰约憾ㄒ逡桓龉乖旌还艽尾淮危嗉鞑辉偬峁┠系牟淮蔚墓乖旌恕9乖旌挥蟹祷刂怠?
BR>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)采用provate继承,基类中的public,protected属性成员访问特性在子类中变为provate.
11,子类和基类的构造函数或析构函数调用顺序:
当调用子类的构造函数时候先调用基类的构造函数(如果没有指明,则调用基类却省那个不带参数的构造函数;如果要指明则在子类构造函数名后加":
基类名(参数)")。
析构函数则相反,先调用子类析构函数,后调用基类的析构函数。
12,函数的覆盖:
函数的覆盖是发生在发生父类和子类之间的。
(函数的重载是发生在同一个类中)
当子类中重写了父类的某些成员函数后,子类中的成员函数覆盖了父类的对应同名成员函数。
13,用父类指针访问子类对象成员时候,只能访问子类从父类继承来的那部分。
(这时候外部不可以访问父类中保护和私有的部分,子类中不可访问父类私有部分。
)
14,多态性:
在基类的的成员函数前加virturl变成虚函数,当用子类对象调用该功能的成员函数时候,子类有的就调用子类的,子类没有的就调用基类的。
当C++编译器在编译的时候,发现被调用的成员函数在基类中定义的是虚函数,这个时候C++就会采用迟绑定技术(latebinding),在运行的时候,依据对象的类型来确定调用的哪个函数,子类有调用子类的,子类没有的就调用基类的。
如果基类中的成员函数不是虚函数,则这时候的绑定是早期绑定,在编译的时候就已经确定该调用哪个函数。
15,纯虚函数:
在类中定义时eg:
virtualvoidf1()=0;
纯虚函数没有函数体,含有纯虚函数的类叫做抽象类,抽象类不能实例化对象。
当子类从抽象类的基类中派生出来时候,如果没有实现基类中的纯虚函数,则子类也是个抽象类,也不能实例化对象。
纯虚函数被标名为不具体实现的虚成员函数,纯虚函数可以让类只具有操作的名称而不具有具体的操作的内容,让派生类在继承的时候再给出具体的定义。
如果派生类没有给出基类的纯虚函数的具体定义的时候,派生类也为一个抽象类,也不能实例化对象。
16,引用:
变量的别名。
引用需要在定义的时候用一变量或对象初始化自己。
引用一旦在定义的时候初始化,就维系在一个特定的变量或对象上。
引用不占用物理内存(与定义引用的目标共用同一内存)。
指针变量需要占用物理内存,用来存储地址。
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)采用provate继承,基类中的public,protected属性成员访问特性在子类中变为provate.
11,子类和基类的构造函数或析构函数调用顺序:
当调用子类的构造函数时候先调用基类的构造函数(如果没有指明,则调用基类却省那个不带参数的构造函数;如果要指明则在子类构造函数名后加":
基类名(参数)")。
析构函数则相反,先调用子类析构函数,后调用基类的析构函数。
12,函数的覆盖:
函数的覆盖是发生在发生父类和子类之间的。
(函数的重载是发生在同一个类中)
当子类中重写了父类的某些成员函数后,子类中的成员函数覆盖了父类的对应同名成员函数。
13,用父类指针访问子类对象成员时候,只能访问子类从父类继承来的那部分。
(这时候外部不可以访问父类中保护和私有的部分,子类中不可访问父类私有部分。
)
14,多态性:
在基类的的成员函数前加virturl变成虚函数,当用子类对象调用该功能的成员函数时候,子类有的就调用子类的,子类没有的就调用基类的。
当C++编译器在编译的时候,发现被调用的成员函数在基类中定义的是虚函数,这个时候C++就会采用迟绑定技术(latebinding),在运行的时候,依据对象的类型来确定调用的哪个函数,子类有调用子类的,子类没有的就调用基类的。
如果基类中的成员函数不是虚函数,则这时候的绑定是早期绑定,在编译的时候就已经确定该调用哪个函数。
15,纯虚函数:
在类中定义时eg:
virtualvoidf1()=0;
纯虚函数没有函数体,含有纯虚函数的类叫做抽象类,抽象类不能实例化对象。
当子类从抽象类的基类中派生出来时候,如果没有实现基类中的纯虚函数,则子类也是个抽象类,也不能实例化对象。
纯虚函数被标名为不具体实现的虚成员函数,纯虚函数可以让类只具有操作的名称而不具有具体的操作的内