1.所谓程序执行机制分为:
过程驱动:程序的执行过程总是按照预定好的顺序执行。
事件驱动:程序的执行是无序的,用户可以根据需要随机出发相应的事件。
win32窗口程序就是采用事件驱动方式执行,也就是消息机制。
2.什么是消息?
当系统通知窗口工作时,DispatchMessage函数就采用消息的方式派发给窗口处理函数。
消息的组成:(windows平台下消息必须由这6个部分组成)
窗口句柄
消息ID
消息的两个参数(两个附带信息)
消息的产生时间
消息产生时的鼠标位置
3.DispatchMessage( &nMsg )是怎么派发消息?(其实就是调用我们的窗口处理函数来处理这个消息)
通过nMsg.hWnd保存窗口数据的内存,然后找到窗口对应的窗口类名称,用这个名称去匹配每个窗口类名称。
一旦匹配成功,就直接调用我们自己定义的窗口处理函数。
然后给我们的窗口处理函数传参:WndProc(nMsg.hWnd, nMsg.message, nMsg.wParam, nMsg.lParam)
4.窗口处理函数
(1)每个窗口都必须具有窗口处理函数
LRESULT CALLBACK WindowProc( HWND hWnd, //窗口句柄
UINT uMsg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam); //消息参数
当系统通知窗口时,会调用窗口处理函数,同时将参数(窗口句柄、消息ID、消息两个参数)传递给窗口处理函数。
在窗口处理函数中,不处理的消息,使用缺省窗口处理函数,例如DefWindowProc。
5.消息相关函数
(1)GetMessage - 获取本进程的消息
BOOL GetMessage( LPMSG lpMsg, //存放获取到的消息buffer
HWND hWnd, //窗口句柄
UINT wMsgFilterMin, //获取消息的最小ID
UINT wMsgFilterMax); //获取消息的最大ID
lpMsg - 获取到消息后,将消息的参数存放到MSG结构中
hWnd - 获取到hWnd所指窗口的消息,不获取其他窗口消息;如果为NULL,任意窗口的消息都获取。
wMsgFilterMin和wMsgFilterMax - 只能获取到由它指定的消息范围内的消息,如果都为0,表示没有范围。
如果抓取到的消息是WM_QUIT,那么返回值为0;否则,返回非0。
(2)TranslateMessage - 翻译消息,将按键消息翻译成字符消息
BOOL TranslateMessage( CONST MSG *lpMsg); //消息的地址
检查消息是否是按键的消息,如果不是按键消息,不做任何处理继续执行。
为什么只翻译按键消息,不翻译其他消息呢?因为键盘中的可见字符按键有多种状态(比如大小写)。
(3)DispatchMessage - 派发消息,将消息派发到该消息所属窗口的窗口处理函数上
LRESULT DispatchMessage( CONST MSG *lpMsg); //消息的地址
6.Windows常用消息
(1)WM_DESTROY - 窗口被销毁(保存窗口数据的内存释放)时的消息,无消息参数。常用于在窗口被销毁之前,做相应的善后处理,
例如资源、内存等。
(2)WM_SYSCOMMAND - 系统命令消息,当点击窗口的最大化、最小化、关闭等命令时,收到这个消息,常用在窗口关闭时,提示用户处理。
wPARAM- 具体点击位置,例如关闭SC_CLOSE等。
lPARAM - 鼠标位置:LOWORD - 水平位置,HIWORD - 垂直位置。
(3)WM_CREATE - 在窗口创建成功还未显示之前,收到这个消息。常用于初始化窗口的参数、资源等,包括创建子窗口等。
WPARAM - 不使用。
LPARAM - 是CREATESTRUCT结构指针,保存了CreateWindowEx中的12个参数。
(4)WM_SIZE - 在窗口的大小发生变化后,会收到这个消息。常用于窗口大小变化后,调整窗口内各个部分的布局。
wPARAM - 窗口大小变化的原因。
lPARAM - 变化窗口客户区的大小:LOWORD - 变化后的宽度,HIWORD - 变化后的高度。
(5)WM_QUIT - 用于结束消息循环处理
wPARAM - PostQuitMessage函数传递的参数
lPARAM - 不使用
当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环。
(6)WM_PAINT - 绘图消息
(7)键盘消息
(8)鼠标消息
(9)定时器消息
下面是示例代码:
#include "stdafx.h" HINSTANCE g_hInstance = 0; //接收当前程序实例句柄 //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_SYSCOMMAND: if (SC_CLOSE == wParam) { int nRet = MessageBox(NULL, "是否退出", "Info", MB_YESNO); if (IDNO == nRet) { return 0; } } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName, WNDPROC wndProc) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra = 200; wce.cbClsExtra = 200; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndProc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if (0 == nAtom) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMainWindow(LPSTR lpClassName, LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInstance, NULL); return hWnd; }//显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = { 0 }; while (GetMessage(&nMsg, NULL, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance; Register("Main", WndProc); HWND hWnd = CreateMainWindow("Main", "window"); Display(hWnd); Message(); return 0; }
运行结果: