首页 > 代码库 > 2.窗口与消息

2.窗口与消息

知识点:
1.窗口程序的创建
2.窗口的注册
3.系统窗口类的注册
4.应用程序全局窗口类的注册
5.窗口类的风格
6.窗口类的查找过程
7.相关API
8.窗口的创建
9.子窗口的创建
10.窗口类和窗口的附加数据
11.Windows消息机制
12.什么是消息?
13.窗口处理函数和消息
14.消息相关函数
15.Windows常用消息
16.消息的获取
17.消息的发送
18.消息的分类
19.消息队列
20.消息和消息队列
21.消息的获取
22.GetMessage/PeekMessage次序
23.消息的发送
 
 
正文:

1.窗口程序的创建

窗口程序的创建步骤:
1 定义WinMain入口函数
2 定义窗口处理函数 WindowProc
3 注册窗口类 RegisterClass
4 创建窗口 CreateWindow
5 显示窗口
ShowWindow/UpdateWindow
6 消息循环
GetMessage
TranslateMessage
DisptachMessage
7 消息处理
2.窗口的注册
窗口类
    窗口类包含了窗口的各种参数信息的数据结构。每个窗口都具有窗口类,基于窗口类创建窗口。每个窗口类都具有一个名称,使用前必须注册到系统。
窗口类的分类
    -系统窗口类 
    系统已经定义好的窗口类,所有应用程序都可以直接使用。
    -应用程序全局窗口类 
     由用户自己定义,当前应用程序所有模块都可以使用。
    -应用程序局部窗口类 
     由用户自己定义,当前应用程序中本模块可以使用
 
3.系统窗口类的注册
不需要注册,直接使用窗口类即可。系统
已经定义好相应名称,例如:
    按钮   - BUTTON
    编辑框 - EDIT
 
4.应用程序全局窗口类的注册
RegisterClass/RegisterClassEx
 
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass //窗口类的数据
); 注册成功后,返回一个数字标识。
ATOM RegisterClassEx(
CONST WNDCLASSEX *lpwcx  //窗口类的数据
);
 
typedef struct _WNDCLASSEX {
UINT cbSize;         //结构体的大小
UINT style;         //窗口类的风格
WNDPROC lpfnWndProc;     //窗口处理函数
int cbClsExtra;     //窗口类的附加数据
int cbWndExtra;     //窗口的附加数据
HINSTANCE hInstance;     //当前模块的实例句柄
HICON hIcon;     //窗口图标句柄
HCURSOR hCursor;     //鼠标的句柄
HBRUSH hbrBackground; //绘制窗口背景的画刷句柄
LPCTSTR lpszMenuName; //窗口菜单的资源ID字符串
LPCTSTR lpszClassName; //窗口类的名称
HICON hIconSm; //窗口的小图标句柄
} WNDCLASSEX, *PWNDCLASSEX
应用程序全局窗口类的注册,需要在窗口类的风格中增加 CS_GLOBALCLASS,例如:
    WNDCLASSEX wce = {0};
    wce.style = CS_GLOBALCLASS;
应用程序局部窗口类
    在注册窗口类时,不添加CS_GLOBALCLASS风格。
 
5.窗口类的风格
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8倍数对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置8倍数对齐
CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制 
CS_CLASSDC - 该类型的窗口,都是有同一个绘图(DC)设备 
CS_PARENTDC - 该类型的窗口,使用它的父窗口的绘图(DC)设备
CS_OWNDC - 该类型的窗口,每个窗口都使用自己的绘图(DC)设备
CS_SAVEBITS - 允许窗口保存成图(位图),提高窗口的绘图效率,但是耗费内存资源
CS_DBLCLKS - 允许窗口接收鼠标左键双击
CS_NOCLOSE - 窗口没有关闭按钮
 
6.窗口类的查找过程
1)系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3。
2)比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3。
3) 在应用程序全局窗口类,如果找到,执行4,如果未找到执行5。
4) 使用找到的窗口类的信息,创建窗口返回。
5)在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败。
 
7.相关API
RegisterClass/RegisterClassEx 注册
GetClassInfo 获取信息
UnregisterClass 卸载
 
8.窗口的创建
CreateWindow/CreateWindowEx
HWND CreateWindowEx(
DWORD dwExStyle, //窗口的扩展风格
LPCTSTR lpClassName, //已经注册的窗口类名称
LPCTSTR lpWindowName, //窗口标题栏的名字
DWORD dwStyle, //窗口的基本风格
int x, //窗口左上角水平坐标位置
int y, //窗口左上角垂直坐标位置
int nWidth, //窗口的宽度
int nHeight,//窗口的高度
HWND hWndParent,//窗口的父窗口句柄
HMENU hMenu,//窗口菜单句柄
HINSTANCE hInstance, //应用程序实例句柄
LPVOID lpParam //窗口创建时附加参数
); 创建成功返回窗口句柄
 
9.子窗口的创建
创建时要设置父窗口句柄
创建风格要增加 WS_CHILD|WS_VISIBLE
 
10.窗口类和窗口的附加数据
作用
    注册窗口时,可以设置这两个数据内存空间 的大小。
     int cbClsExtra; //窗口类的附加数据大小
     int cbWndExtra; //窗口的附加数据大小
     可以提供窗口类和窗口存放自己的数据的空间。
 
11.Windows消息机制
程序执行机制
   过程驱动 - 程序的执行过程是按照预定好的顺序执行。
   事件驱动 - 程序的执行是无序,用户可以根据需要随机触发相应的事件。
Win32窗口程序就是采用 事件驱动 方式执行,也就是 消息机制。
 
12.什么是消息?
当系统通知窗口工作时,就采用消息的方式派发给窗口。
消息组成:
窗口句柄
消息ID
消息的两个参数
消息产生的时间
消息产生时的鼠标位置
 
13.窗口处理函数和消息
每个窗口都必须具有窗口处理函数。
LRESULT CALLBACK WindowProc(
    HWND hwnd, //窗口句柄
    UINT uMsg, //消息ID
    WPARAM wParam, //消息参数
    LPARAM lParam  //消息参数
);
当系统通知窗口时,会调用窗口处理函数同时,将消息ID和消息参数传递给窗口处理函数。
在窗口处理函数中,不处理的消息,使用缺省窗口处理函数,例如DefWindowProc。
 
14.消息相关函数
1)GetMessage - 获取消息。
BOOL GetMessage(
LPMSG lpMsg, //存放获取到的消息BUFF
HWND hWnd, //窗口句柄
 UINT wMsgFilterMin,//获取消息的最小ID
UINT wMsgFilterMax   //获取消息的最大ID
);
lpMsg - 当获取到消息后,将消息的参数存放到MSG结构中。
hWnd - 获取到hWnd所指定窗口的消息。
wMsgFilterMin和wMsgFilterMax -只能获取到由它们指定的消息范围内的消息,如果都为0,表示没有范围。
2) TranslateMessage - 翻译消息。将按键消息,翻译成字符消息。
    BOOL TranslateMessage(
     CONST MSG *lpMsg //要翻译的消息地址
    );
    检查消息是否是按键的消息,如果不是按键消息,不做任何处理,继续执行。
3) DispatchMessage - 派发消息。将消息派发到该消息所属窗口的窗口处理函数上。
    LRESULT DispatchMessage(
    CONST MSG *lpmsg //要派发的消息
);
 
15.Windows常用消息
WM_DESTROY - 窗口被销毁时的消息,无消息参数。常用于在窗口被销毁之前,做相应的善后处理,例如资源、内存等。
WM_SYSCOMMAND - 系统命令消息,当点击窗口的最大化、最小化、关闭等命令时,收到这个消息。
常用在窗口关闭时,提示用户处理。
    wParam - 具体命令,例如关闭SC_CLOSE等.
    lParam - 鼠标位置
    LOWORD 低字 - 水平位置
    HIWORD 高字 - 垂直位置
WM_CREATE - 在窗口创建成功还未显示之前,收到这个消息。
常用于初始化窗口的参数、资源等等,包括创建子窗口等。
WPARAM - 不使用
LPARAM - 是CREATESTRUCT结构的指针,保存了CreatWindowEx中的12个参数。
WM_SIZE - 在窗口的大小发生变化后,会收到WM_SIZE。
常用于窗口大小变化后,调整窗口内各个部分的布局。
WPARAM - 窗口大小变化的原因。
LPARAM - 变化窗口客户区的大小
LOWORD - 变化后的宽度
HIOWORD- 变化后的高度
WM_QUIT - 用于结束消息循环处理。
wParam - PostQuitMessage 函数传递的参数。
lParam - 不使用
当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环。
WM_PAINT - 绘图消息
键盘消息
鼠标消息
定时器消息
 
16.消息的获取
GetMessage - 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,GetMessage会等候下一条消息。
PeekMessage - 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。
BOOL PeekMessage(
LPMSG lpMsg,         // message information
HWND hWnd,           // handle to window
UINT wMsgFilterMin,  // first message
UINT wMsgFilterMax,  // last message
UINT wRemoveMsg //移除标识
);
 
17.消息的发送
SendMessage - 发送消息,会等候消息处理的结果。
PostMessage - 投递消息,消息发出后立刻返回,不等候消息执行结果。
    BOOL SendMessage/PostMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam  //消息参数
);
 
18.消息的分类
1 系统消息 - ID范围 0 - 0x03FF 
由系统定义好的消息,可以在程序中直接使用。
2 用户自定义消息 - ID范围 0x0400 - 0x7FFF 
由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理。
自定义消息宏:WM_USER 
3 应用程序消息 - ID范围 0x8000 - 0xBFFF 
程序之间通讯时使用的消息。
应用程序消息宏:WM_APP 
4 系统注册消息 - ID范围 0xC000 - 0xFFFF 
在系统注册并生成相应消息,然后可以在各个程序中使用这个消息。
 
19.消息队列
消息队列用于存放消息的一个队列,消息在队列中先入先出。所有窗口程序都具有消息队列。程序可以从队列中获取消息。
消息队列的类型
系统消息队列-由系统维护的消息队列。存放系统产生的消息,例如鼠标、键盘等。
程序消息队列-属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护。
消息队列的关系
1 当鼠标、键盘产生消息时,会将消息存放到系统消息队列
2 系统会根据存放的消息,找到对应窗口的消息队列。
3 将消息投递到程序的消息队列中。
 
20.消息和消息队列
根据消息和消息队列之间使用关系,将消息分成两类:
队列消息 - 消息的发送和获取,都是通过消息队列完成。
非队列消息 - 消息的发送和获取,是直接调用消息的窗口处理完成。
队列消息-消息发送后,首先放入队列,然后通过消息循环,从队列当中获取。
GetMessage - 从消息队列中获取消息
PostMessage - 将消息投递到消息队列
常见队列消息:WM_PAINT、键盘、鼠标、定时器。
非队列消息-消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用处理函数,完成消息。
SendMessage - 直接将消息发送给窗口的处理函数,并等候处理结果。
常见消息:WM_CREATE、WM_SIZE等。
 
21.消息的获取
消息循环
GetMessage /PeekMessage从程序的消息队列当中,获取到消息。
TranslateMessage 检查获取到的消息,如果发现是按键消息,产生一个字符消息,并放入程序的消息队列。
DispatchMessage 根据消息,找到窗口处理函数,调用窗口处理函数,完成消息的处理。
 
22.GetMessage/PeekMessage次序
1 在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(HWND,ID范围),不满足条件就不会取出消息,否则从队列取出消息返回。
2 如果程序(线程)消息队列没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程
3 如果系统消息队列也没有消息,检查当前窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生WM_PAINT消息,取得消息返回处理。
4 如果没有重新绘制区域,检查定时器如果有到时的定时器,产生WM_TIMER,返回处理执行。
5 如果没有到时的定时器,整理程序的资源、内存等等。
6 GetMessage会继续等候下一条消息。PeekMessage会返回FALSE,交出程序的控制权。
注意:GetMessage如果获取到是WM_QUIT,函数会返回FALSE。
 
23.消息的发送
1 SendMessage
发送消息到指定的窗口,并等候对方将消息处理,然后消息执行结果,用于非队列消息的发送。
2 PostMessage
将消息放到消息队列中,立刻返回,用于队列消息的发送。
无法获知消息是否被对方处理。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

2.窗口与消息