抓取消息:
GetMessage:从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,会等候下一条消息。
PeekMessage:以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。
BOOL PeekMessage(
LPMSG lpMsg,// message information
HWND hWnd,//handle to window
UINT wMsgFilterMin,//first message
UINT wRemoveMsg//移除标识
PM_REMOVE/PM_NOREMOVE
);
发送消息:
SendMessage:发送消息,会等候消息处理的结果。
PostMessage:投递消息,消息发出后立刻返回,不等候消息的执行结果。
BOOL SendMessage/PostMessage(
HWND hWnd, //消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam //消息参数
);
消息的分类:
系统消息:ID范围0-0x03ff
由系统定义好的消息,可以在程序中直接使用。
用户自定义消息:ID范围0x0400-0x7fff(31743)
由用户自定义,满足用户自己的需求。
由用户自己发出消息,并相应处理。
自定义消息宏:WM_USER
消息队列:
每个窗口程序都有消息队列
程序可以冲队列中获取消息
只有GetMessage会到消息队列中抓消息
GetMessage只能从消息队列抓消息
系统消息队列:由系统维护的消息队列。存放系统产生的消息,例如鼠标、键盘。
程序消息队列:属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护。
消息和消息队列的关系:
当鼠标、键盘产生消息,会将消息存放到系统消息队列,然后系统找到对应程序把消息投递到程序的消息队列中
根据消息和消息队列之间的使用关系,消息分两类:
队列消息:消息的发送和获取,都是通过消息队列完成。
非队列消息:消息的发送和获取,是直接调用消息的窗口处理完成。
队列消息:消息发送后,先进队列,然后通过消息循环,从队列中获取。
GetMessage:从消息队列获取消息
PostMessage:将消息投递到消息队列
常见队列消息:WM_QUIT、WM_PAINT、键盘、鼠标、定时器。
非队列消息:消息发送时,首先查找消息接收窗口的处理函数,直接调用处理函数,完成消息。
SendMessage:直接将消息发送给窗口处理函数,并等候处理结果。
常见的非队列消息:WM_CREATE、WM_SIZE等。
大多数消息本身没有队列或者非队列的属性。取决于程序员是否让他进队列。
GetMessage详解:
在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(HWND, ID范围),不满足条件就不会取出消息,否则从队列取出消息返回。
如果程序(线程)消息队列没有消息,GetMessage会向系统质询,系统会检查系统消息队列,如果有该程序的消息,系统会将消息转发到程序消息队列中。
如果系统消息队列也没有消息,检查当前进程的所有窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生WM_PAINT消息,发送到系统消息队列,系统将它投递到程序消息队列,GetMessage从程序消息队列中取得此消息返回处理。
如果没有重新绘制的区域,检查定时器如果有到时的定时器,产生WM_TIMER,和上述过程一样返回处理执行。
如果没有到时的定时器,整理程序的资源、内存等等。
GetMessage会继续等候下一条消息。PeekMessage会返回FALSE,交出程序的控制权。
注意:GetMessage如果获取到的是WM_QUIT,函数会返回FALSE。
WM_PAINT消息:
产生时间:当窗口需要绘制而且GetMessage没抓到消息的时候。还有ShowWindow的时候。
附带消息:wParam: 0。
lParam: 0。
专职用法:用于绘图。
窗口无效区域:需要重新绘制的区域。
BOOL InvalidateRect(
//这个函数一调,说明需要重绘窗口了。
HWND hWnd,//窗口句柄
CONST RECT* lpRect,//区域的矩形坐标
BOOL bErase//重绘前是否先擦除
);
WMP_PAINT消息处理步骤:
1.开始绘图
HDC BeginPaint(
HWND hWnd,
LPPAINTSTRUCT lpPaint//绘图参数的缓冲区
);返回绘图设备句柄HDC
2.正式绘图
3.结束绘图
BOOL EndPaint(
HWND hWnd
CONST PAINTSTRUCT* lpPaint //绘图参数的指针BeginPaint返回
);
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#define WM_MYMESSAGE WM_USER//WM_USER的取值是0x0400,从他开始包括他往后31742个字节都可以自定义消息。
HANDLE g_hOutput = 0; //接受标准输出句柄
void OnCreate(HWND hWnd, LPARAM lParam) {
CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
char* pszText = (char*)pcs->lpCreateParams;
MessageBox(NULL, pszText, "Infor", MB_OK);
PostMessage(hWnd, WM_MYMESSAGE, 1, 2);
CreateWindowEx(0, "EDIT", "hello", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);
}
void OnSize(HWND hWnd, LPARAM lParam) {
short nWidth = LOWORD(lParam);
short nHeight = HIWORD(lParam);
char szText[256] = { 0 };
sprintf(szText, "WM_SIZE:宽:%d, 高:%d\n", nWidth, nHeight);
WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL);
}
void OnMyMessage(HWND hWnd, WPARAM wParam, LPARAM lParam) {
char szText[256] = { 0 };
sprintf(szText, "自定义消息被处理:wParam = %d, lParam = %d\n", wParam, lParam);
MessageBox(hWnd, szText, "Infor", MB_OK);
}
void OnPaint(HWND hWnd) {
char pszText[] = TEXT("WM_PAINT\n");
WriteConsole(g_hOutput, pszText, strlen(pszText), NULL, NULL);
PAINTSTRUCT ps{ 0 };
HDC hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 100, 100, "hello", 5);
EndPaint(hWnd, &ps);
}
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msgId, WPARAM wParam, LPARAM lParam) {
switch (msgId) {
case WM_LBUTTONDOWN:
//InvalidateRect(hWnd, NULL, true);
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_MYMESSAGE:
OnMyMessage(hWnd, wParam, lParam);
break;
case WM_SIZE:
OnSize(hWnd, lParam);
break;
case WM_CREATE:
OnCreate(hWnd, lParam);
break;
case WM_DESTROY:
//PostQuitMessage(0);
PostMessage(hWnd, WM_QUIT, 0, 0);
break;
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE) {
int nRet = MessageBox(hWnd, "是否退出", "注意", MB_YESNO);
if (nRet != IDYES) {
return 0;
}
break;
}
}
return DefWindowProc(hWnd, msgId, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
AllocConsole();//增加dos窗口
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//注册窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hIns;
wc.lpfnWndProc = WndProc;
TCHAR name[] = TEXT("Main");
wc.lpszClassName = name;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);//将以上所有赋值全部写入操作系统。
char pszText[] = "hello data";
//在内存中创建窗口
HWND hWnd = CreateWindow(name, TEXT("title"), WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, pszText);
//注册子窗口类
wc = { 0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hIns;
wc.lpfnWndProc = DefWindowProc;
TCHAR name1[] = TEXT("Child");
wc.lpszClassName = name1;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);//将以上所有赋值全部写入操作系统。
//在内存中创建子窗口
//HWND hChild1 = CreateWindowEx(0, name1, TEXT("ChildTitle"), WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
//HWND hChild2 = CreateWindowEx(0, "Child", "c2", WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//消息循环
MSG nMsg = { 0 };
while (1) {
if (PeekMessage(&nMsg, NULL, 0, 0, PM_NOREMOVE)) {
//有消息
if (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
}
else return 0;
}
else {
//没消息,空闲处理
char temp[] = "1 2 3 4 5 6 7 8 9 ";
WriteConsole(g_hOutput, temp, strlen(temp), NULL, NULL);
}
}
return 0;
}