win 32学习笔记(三) 消息队列

抓取消息:
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;
}

你可能感兴趣的:(win32学习笔记,c++)