1、Windows消息运行原理 孙鑫讲座笔记学习Windows消息运行原理 孙鑫讲座笔记学习(1)Windows程序内部运行机制 1,windows程序设计是种事件驱动方式的程序设计,主要基于消息的。当用户需要完成某种功能时,需要调用OS某种支持,然后OS将用户的需要包装成消息,并投入到消息队列中,最后应用程序从消息队列中取走消息并进行响应。2,消息结构:typedef struct tagMSG / msg HWND hwnd; /接收消息的窗口句柄。和哪个窗口相关联。 UINT message; /消息标识。消息本身是什么。 WPARAM wParam; /消息的附加信息。具体取决于消息本身。
2、 LPARAM lParam; DWORD time; /消息投递时间。 POINT pt; /消息投递时,光标在屏幕上的位置。 MSG; 3,消息队列:每个应用程序OS都为它建立一个消息队列,消息队列是个先进先出的缓冲区,其中每个元素都是一个消息,OS将生成的每个消息按先后顺序放进消息队列中,应用程序总是取走当前消息队列中的第一条消息,应用程序取走消息后便知道用户的操作和程序的状态,然后对其处理即消息响应,消息响应通过编码实现。4,使用VC编程除了良好的C基础外还需要掌握两方面:一,消息本身。不同消息所代表的用户操作和应用程序的状态。二,对于某个特定的消息来说,要让OS执行某个特定的功能去响
3、应消息。5,Window程序入口:int WINAPI WinMain( HINSTANCE hInstance, / 当前事例句柄。 HINSTANCE hPrevInstance, / 先前事例句柄。 LPSTR lpCmdLine, / 命令行指针 int nCmdShow / (窗口)显示的状态);说明:WinMain函数是Windows程序入口点函数,由OS调用,当OS启动应用程序的时候,winmain函数的参数由OS传递的。6,创建一个完整的窗口需要经过下面四个操作步骤:一,设计一个窗口类;如:WNDCLASS wndcls;二,注册窗口类; 如:RegisterClass(&wn
4、dcls);三,创建窗口; 如:CreateWindow(),CreateWindowEX();四,显示及更新窗口。如:ShowWindow(),UpdateWindow();说明:创建窗口的时候一定要基于已经注册的窗口类.7,Windows提供的窗口类:typedef struct _WNDCLASS UINT style; /窗口的类型 WNDPROC lpfnWndProc; /窗口过程函数指针(回调函数) int cbClsExtra; /窗口类附加字节,为该类窗口所共享。通常0。 int cbWndExtra; /窗口附加字节。通常设为0。 HANDLE hInstance; /当前
5、应用程序事例句柄。 HICON hIcon; /图标句柄 LoadIcon(); HCURSOR hCursor; /光标句柄 LoadCursor(); HBRUSH hbrBackground; /画刷句柄 (HBRUSH)GetStockObject(); LPCTSTR lpszMenuName; /菜单名字 LPCTSTR lpszClassName; /类的名字 WNDCLASS; 8,窗口类注册:ATOM RegisterClass( CONST WNDCLASS *lpWndClass / address of structure with class / data);9,创建
6、窗口:HWND CreateWindow( LPCTSTR lpClassName, / pointer to registered class name LPCTSTR lpWindowName, / pointer to window name DWORD dwStyle, / window style int x, / horizontal position of window int y, / vertical position of window int nWidth, / window width int nHeight, / window height HWND hWndPare
7、nt, / handle to parent or owner window HMENU hMenu, / handle to menu or child-window identifier HANDLE hInstance, / handle to application instance LPVOID lpParam / pointer to window-creation data);10,显示和更新窗口窗口:BOOL ShowWindow( HWND hWnd, / handle to window int nCmdShow / show state of window);BOOL U
8、pdateWindow( HWND hWnd / handle of window);11,消息循环:MSG msg;while(GetMessage(&msg,.) /从消息队列中取出一条消息TranslateMessage(&msg); /进行消息(如键盘消息)转换DispatchMessage(&msg); /分派消息到窗口的回调函数处理,(OS调用窗口回调函数进行处理)。其中:/*The GetMessage function retrieves a message from the calling threads message queue and places it in the
9、specified structure. /*If the function retrieves a message other than WM_QUIT, the return value is nonzero.If the function retrieves the WM_QUIT message, the return value is zero. If there is an error, the return value is -1. BOOL GetMessage( LPMSG lpMsg, / address of structure with message HWND hWn
10、d, / handle of window UINT wMsgFilterMin, / first message UINT wMsgFilterMax / last message);/The TranslateMessage function translates virtual-key messages into character messages. The character messages are posted to the calling threads message queue, to be read the next time the thread calls the G
11、etMessage or PeekMessage function. BOOL TranslateMessage( CONST MSG *lpMsg / address of structure with message);/The DispatchMessage function dispatches a message to a window procedure. LONG DispatchMessage( CONST MSG *lpmsg / pointer to structure with message);12,窗口过程函数(回调函数)原型:The WindowProc funct
12、ion is an application-defined function that processes messages sent to a window. The WNDPROC type defines a pointer to this callback function. WindowProc is a placeholder(占位符) for the application-defined function name. LRESULT CALLBACK WindowProc( /这里WindowProc是个代号名字。 HWND hwnd, / handle to window U
13、INT uMsg, / message identifier WPARAM wParam, / first message parameter LPARAM lParam / second message parameter);说明:两种函数调用约定(_stdcall 和 _cdecl):#define CALLBACK _stdcall /_stdcall 标准调用预定,是PASCAL 调用约定,象DELPHI使用的就是标准调用约定#define WINAPIV _cdecl / _cdecl 是C 语言形式的调用约定。主要区别:函数参数传递顺序 和 对堆栈的清除上。问题:除了那些可变参数的
14、函数调用外,其余的一般都是_stdcall约定。但 C/C+编译默然的是_cdecl约定。所以如果在VC等环境中调用_stdcall约定的函数,必须要在函数声明的时加上 _stdcall 修饰符,以便对这个函数的调用是使用_stdcall约定(如使用DELPHI编写的DLL时候)。(VC中可通过这途径修改:project|settings.|c/c+|.)在窗口过程函数中通过一组switch语句来对消息进行处理:如:LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) switch(u
15、Msg) case WM_PAINT: . break;case . break;case WM_CLOSE: /DestroyWindow(hwnd); /销毁窗口,并发送WM_DESTROY消息。 break;case WM_DESTROY: /PostQuitMessage(0); /发送WM_QUIT消息到消息队列中,请求终止。 /GetMessage()取到WM_QUIT消息后,返回0,退出消息循 / 环,从而终止应用程序。 break;default: return DefWindowProc(hwnd,uMsg,wParam,lParam);/用缺省的窗口过程处理我们不感兴趣的消
16、息(其它消息)。/这是必须的。 /switchreturn 0;/WindowProc13,DestroyWindow()函数和PostQuitMessage()函数原型:/*The DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages。BOOL DestroyWindow( HWND hWnd / handle to window to destroy);/*The PostQuitMessage function indica
17、tes to the system that a thread has made a request to terminate (quit). It is typically used in response to a WM_DESTROY message. /*The PostQuitMessage function posts a WM_QUIT message to the threads message queue and returns immediately; the function simply indicates(预示,通知) to the system that the t
18、hread is requesting to quit at some time in the future. When the thread retrieves the WM_QUIT message from its message queue, it should exit its message loop and return control to the system.VOID PostQuitMessage( int nExitCode / exit code);14,关于DC句柄获取:a)使用BeginPaint(),EndPaint()对。注意只能在响应WM_PAINT消息时使
19、用。b)使用GetDc(),ReleaseDC()对。注意他们不能在响应WM_PAINT中使用。(2)C+ 1, c语言中,结构体struct中不能包括函数的,而在C+中struct中可以包括函数。2,C+中结构体和类可以通用,区别主要表现在访问控制方面:struct中默认是public,而 class中默认的是private。3,构造函数最重要的作用是创建对象的本身,C+中每个类可以拥有多个构造函数,但必须至少有一个构造函数,当一个类中没有显式提供任何构造函数,C+编辑器自动提供一个默认的不带参数的构造函数,这个默认的构造函数只负责构造对象,不做任何初始化工作 谝桓隼嘀兄灰 约憾逡桓龉乖旌
20、还艽 尾淮 危 嗉 鞑辉偬峁 系牟淮 蔚墓乖旌 恕乖旌 挥蟹祷刂怠?BR4,析构函数当一个对象生命周期结束时候被调用来回收对象占用的内存空间。一个类只需有一个析构函数。析构函数没有返回值也不的带参数。5,析构函数的作用与构造函数相反,对象超出起作用范围对应的内存空间被系统收回,或被程序用delete删除的时候,对象的析构函数被调用。6,函数的重载条件:函数的参数类型、个数不同,才能构成函数的重载。重载是发生在同一个类中。7,类是抽象的,不占用具体物理内存,只有对象是实例化的,是占用具体物理内存的。8,this指针是隐含指针,指向对象本身(this指针不是指向类的),代表了对象的地址。所有的对象
21、调用的成员函数都是同一代码段,但每个对象都有自己的数据成员。当对象通过调用它的成员函数来访问它的数据成员的时候,成员函数除了接收实参外,还接收了对象的地址,这个地址被一个隐藏的形参this所获取,通过这个this指针可以访问对象的数据成员和成员函数。9,对象中public属性的成员在外部和子类中都可以被访问;protected属性的成员在外部不能被访问,在子类中是可以访问的;private属性在子类中和外部都不能被访问。10,类的继承访问特性:(public,protected,private)a)基类中private属性成员,子类无论采用那种继承方式都不能访问。b)采用public继承,基类
22、中的public,protected属性的成员访问特性在子类中仍然保持一致。c)采用protected继承,基类中的public,protected属性成员访问特性在子类中变为protected.d)采用provate继承,基类中的public,protected属性成员访问特性在子类中变为provate.11,子类和基类的构造函数或析构函数调用顺序:当调用子类的构造函数时候先调用基类的构造函数(如果没有指明,则调用基类却省那个不带参数的构造函数;如果要指明则在子类构造函数名后加:基类名(参数))。析构函数则相反,先调用子类析构函数,后调用基类的析构函数。12,函数的覆盖:函数的覆盖是发生在发
23、生父类和子类之间的。(函数的重载是发生在同一个类中)当子类中重写了父类的某些成员函数后,子类中的成员函数覆盖了父类的对应同名成员函数。13,用父类指针访问子类对象成员时候,只能访问子类从父类继承来的那部分。(这时候外部不可以访问父类中保护和私有的部分,子类中不可访问父类私有部分。)14,多态性:在基类的的成员函数前加virturl变成虚函数,当用子类对象调用该功能的成员函数时候,子类有的就调用子类的,子类没有的就调用基类的。当C+编译器在编译的时候,发现被调用的成员函数在基类中定义的是虚函数,这个时候C+就会采用迟绑定技术(late binding),在运行的时候,依据对象的类型来确定调用的哪
24、个函数,子类有调用子类的,子类没有的就调用基类的。如果基类中的成员函数不是虚函数,则这时候的绑定是早期绑定,在编译的时候就已经确定该调用哪个函数。15,纯虚函数:在类中定义时 eg: virtual void f1()=0;纯虚函数没有函数体,含有纯虚函数的类叫做抽象类,抽象类不能实例化对象。当子类从抽象类的基类中派生出来时候,如果没有实现基类中的纯虚函数,则子类也是个抽象类,也不能实例化对象。纯虚函数被标名为不具体实现的虚成员函数,纯虚函数可以让类只具有操作的名称而不具有具体的操作的内容,让派生类在继承的时候再给出具体的定义。如果派生类没有给出基类的纯虚函数的具体定义的时候,派生类也为一个抽
25、象类,也不能实例化对象。16,引用:变量的别名。引用需要在定义的时候用一变量或对象初始化自己。引用一旦在定义的时候初始化,就维系在一个特定的变量或对象上。引用不占用物理内存(与定义引用的目标共用同一内存)。指针变量需要占用物理内存,用来存储地址。1, c语言中,结构体struct中不能包括函数的,而在C+中struct中可以包括函数。2,C+中结构体和类可以通用,区别主要表现在访问控制方面:struct中默认是public,而 class中默认的是private。3,构造函数最重要的作用是创建对象的本身,C+中每个类可以拥有多个构造函数,但必须至少有一个构造函数,当一个类中没有显式提供任何构造
26、函数,C+编辑器自动提供一个默认的不带参数的构造函数,这个默认的构造函数只负责构造对象,不做任何初始化工作。但在一个类中只要自己定义一个构造函数,不管带参不带参,编辑器不再提供默认的不带参的构造函数了。构造函数没有返回值。4,析构函数当一个对象生命周期结束时候被调用来回收对象占用的内存空间。一个类只需有一个析构函数。析构函数没有返回值也不的带参数。5,析构函数的作用与构造函数相反,对象超出起作用范围对应的内存空间被系统收回,或被程序用delete删除的时候,对象的析构函数被调用。6,函数的重载条件:函数的参数类型、个数不同,才能构成函数的重载。重载是发生在同一个类中。7,类是抽象的,不占用具体
27、物理内存,只有对象是实例化的,是占用具体物理内存的。8,this指针是隐含指针,指向对象本身(this指针不是指向类的),代表了对象的地址。所有的对象调用的成员函数都是同一代码段,但每个对象都有自己的数据成员。当对象通过调用它的成员函数来访问它的数据成员的时候,成员函数除了接收实参外,还接收了对象的地址,这个地址被一个隐藏的形参this所获取,通过这个this指针可以访问对象的数据成员和成员函数。9,对象中public属性的成员在外部和子类中都可以被访问;protected属性的成员在外部不能被访问,在子类中是可以访问的;private属性在子类中和外部都不能被访问。10,类的继承访问特性:(
28、public,protected,private)a)基类中private属性成员,子类无论采用那种继承方式都不能访问。b)采用public继承,基类中的public,protected属性的成员访问特性在子类中仍然保持一致。c)采用protected继承,基类中的public,protected属性成员访问特性在子类中变为protected.d)采用provate继承,基类中的public,protected属性成员访问特性在子类中变为provate.11,子类和基类的构造函数或析构函数调用顺序:当调用子类的构造函数时候先调用基类的构造函数(如果没有指明,则调用基类却省那个不带参数的构造函数
29、;如果要指明则在子类构造函数名后加:基类名(参数))。析构函数则相反,先调用子类析构函数,后调用基类的析构函数。12,函数的覆盖:函数的覆盖是发生在发生父类和子类之间的。(函数的重载是发生在同一个类中)当子类中重写了父类的某些成员函数后,子类中的成员函数覆盖了父类的对应同名成员函数。13,用父类指针访问子类对象成员时候,只能访问子类从父类继承来的那部分。(这时候外部不可以访问父类中保护和私有的部分,子类中不可访问父类私有部分。)14,多态性:在基类的的成员函数前加virturl变成虚函数,当用子类对象调用该功能的成员函数时候,子类有的就调用子类的,子类没有的就调用基类的。当C+编译器在编译的时
30、候,发现被调用的成员函数在基类中定义的是虚函数,这个时候C+就会采用迟绑定技术(late binding),在运行的时候,依据对象的类型来确定调用的哪个函数,子类有调用子类的,子类没有的就调用基类的。如果基类中的成员函数不是虚函数,则这时候的绑定是早期绑定,在编译的时候就已经确定该调用哪个函数。15,纯虚函数:在类中定义时 eg: virtual void f1()=0;纯虚函数没有函数体,含有纯虚函数的类叫做抽象类,抽象类不能实例化对象。当子类从抽象类的基类中派生出来时候,如果没有实现基类中的纯虚函数,则子类也是个抽象类,也不能实例化对象。纯虚函数被标名为不具体实现的虚成员函数,纯虚函数可以让类只具有操作的名称而不具有具体的操作的内
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1