win 32 learning note message queue

Posted by AdamSnow on Tue, 04 Jan 2022 19:31:32 +0100

Grab message:
GetMessage: get the message from the system, remove the message from the system, and block the function. When the system has no message, it will wait for the next message.
PeekMessage: get messages from the system by viewing. Messages can not be removed from the system. It is a non blocking function. When there is no message in the system, return FALSE and continue to execute subsequent codes.
BOOL PeekMessage( 
        LPMSG lpMsg,// message information
        HWND hWnd,//handle to window
        UINT wMsgFilterMin,//first message
UINT wRemoveMsg / / remove identity
        PM_REMOVE/PM_NOREMOVE
); 
Send message:
SendMessage: Send a message and wait for the result of message processing.
PostMessage: post a message. It returns immediately after the message is sent. It does not wait for the execution result of the message.
BOOL SendMessage/PostMessage(
HWnd, hWnd, / / destination window of message sending
UINT Msg, / / message ID
WPARAM wParam, / / message parameters
LPARAM lParam / / message parameters
);

Classification of messages:
System message: ID range 0-0x03ff
Messages defined by the system can be used directly in the program.
User defined message: ID range 0x0400-0x7fff(31743)
Customized by users to meet their own needs.
The user sends a message and processes it accordingly.
Custom message macros: WM_USER

Message queuing:
Each windower has a message queue
The program can get messages from the queue
Only GetMessage will grab messages in the message queue
GetMessage can only grab messages from the message queue
System message queue: a message queue maintained by the system. Store messages generated by the system, such as mouse and keyboard.
Application message queue: the message queue belonging to each application (thread). Maintained by the application (thread).
Relationship between message and message queue:
When a message is generated by the mouse and keyboard, the message will be stored in the system message queue, and then the system will find the corresponding program and deliver the message to the program message queue
According to the usage relationship between messages and message queues, messages are divided into two categories:
Message queue: sending and obtaining messages are completed through message queue.
Non queued message: the sending and obtaining of a message is completed by directly calling the window processing of the message.
Queue message: after a message is sent, it is queued first, and then obtained from the queue through message circulation.
GetMessage: get message from message queue
PostMessage: post message to message queue
Common queue messages: WM_QUIT,WM_PAINT, keyboard, mouse, timer.
Non queue message: when sending a message, first find the processing function of the message receiving window and directly call the processing function to complete the message.
SendMessage: send the message directly to the window processing function and wait for the processing result.
Common non queued messages: WM_CREATE,WM_SIZE et al.
Most messages themselves do not have queue or non queue properties. It depends on whether the programmer puts him in the queue.

GetMessage details:
Find the message in the program (thread) message queue. If there is a message in the queue, check whether the message meets the specified conditions (HWND, ID range). If the conditions are not met, the message will not be taken out. Otherwise, the message will be taken out from the queue and returned.
If there is no message in the program (thread) message queue, GetMessage will challenge the system, and the system will check the system message queue. If there is a message from the program, the system will forward the message to the program message queue.
If there are no messages in the system message queue, check the areas to be redrawn in all windows of the current process. If there are areas to be redrawn, WM is generated_ Paint message is sent to the system message queue. The system delivers it to the program message queue. GetMessage obtains this message from the program message queue and returns it for processing.
If there is no redrawn area, check the timer. If there is a timer when it expires, WM will be generated_ Timer, like the above procedure, returns to the processing execution.
If there is no timer when the time is up, organize the program's resources, memory, etc.
GetMessage will continue to wait for the next message. PeekMessage will return FALSE and hand over control of the program.
Note: if WM is obtained by GetMessage_ Quit, the function returns FALSE.

WM_PAINT message:
Generation time: when the window needs to be drawn and GetMessage does not catch the message. And ShowWindow.
Accompanying message: wParam: 0.
    lParam: 0.
Professional usage: used for drawing.
Invalid area of window: area that needs to be redrawn.
BOOL InvalidateRect(
//Once this function is adjusted, it indicates that the window needs to be redrawn.
HWnd, / / window handle
CONST RECT* lpRect, / / rectangular coordinates of the area
Bool erase / / erase before redrawing
);
WMP_PAINT message processing steps:
1. Start drawing
HDC BeginPaint(
    HWND hWnd, 
LPPAINTSTRUCT lpPaint / / buffer for drawing parameters
); Return drawing device handle HDC
2. Formal drawing
3. End drawing
BOOL EndPaint(
    HWND hWnd
CONST PAINTSTRUCT* lpPaint / / the pointer of the drawing parameter BeginPaint returns
);

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#define WM_ MYMESSAGE WM_ USER//WM_ The value of user is 0x0400. You can customize the message from him, including 31742 bytes later.
HANDLE g_hOutput = 0; //Accept standard output handle
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: Width:%d, Height:%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, "Custom message processed: 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);
}
//Window processing function (custom, message processing)
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, "Exit", "be careful", MB_YESNO);
			if (nRet != IDYES) {
				return 0;
			}
			break;
		} 
	}
	return DefWindowProc(hWnd, msgId, wParam, lParam);
}

//Entry function
int  CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
	AllocConsole();//Add dos window
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//Register window class
	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);//Write all the above assignments to the operating system.
	
	char pszText[] = "hello data";
	//Create a window in memory
	HWND hWnd = CreateWindow(name, TEXT("title"), WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, pszText);

	//Register child window classes
	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);//Write all the above assignments to the operating system.
	//Create child windows in memory
	//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);
	//Display window
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//Message loop
	MSG nMsg = { 0 };
	while (1) {
		if (PeekMessage(&nMsg, NULL, 0, 0, PM_NOREMOVE)) {
			//There's news
			if (GetMessage(&nMsg, NULL, 0, 0)) {
				TranslateMessage(&nMsg);
				DispatchMessage(&nMsg);//Give the message to the window handler
			}
			else return 0;
		}
		else {
			//No processing, no processing
			char temp[] = "1	2	3	4	5	6	7	8	9	";
			WriteConsole(g_hOutput, temp, strlen(temp), NULL, NULL);
		}
	}
	return 0;
}

Topics: C++