In the article "message mechanism of programming thought", we talk about the concept of the message and the simulation of the message mechanism, this article will further talk about the message mechanism in C + +.
Analysis of core principles from simple examples
Before we talk, let's look at a simple example: Create a window and two buttons to control the background color of the window. The effect is as follows:
Figure 2:
Win32Test.h
#pragma once#include <windows.h>#include <atltypes.h>#include <tchar.h>//resource ID#define ID_BUTTON_DRAW#define ID_BUTTON_SWEEP 1001//Registration window classATOM Appregisterclass (hinstance hinstance);//Initialization windowBOOL InitInstance (HINSTANCE,int);//Message handler function (also called window procedure)LRESULTCALLBACKWndProc (HWND, UINT, WPARAM, LPARAM);//(white background) button eventvoidOnbuttonwhite ();//(gray Background) button eventvoidOnbuttongray ();//Draw EventsvoidOnDraw (hdc hdc);
Win32Test.cpp
#include "stdafx.h"#include "Win32Test.h"//character array length#define Max_loadstring//global variableHINSTANCE HInst;//Current instanceTCHAR g_sztitle[max_loadstring] = TEXT ("Message Process");//Window titleTCHAR g_szwindowclass[max_loadstring] = TEXT ("Apptest");//Name of the window classHWND G_hwnd;//Window handleBOOLG_bwhite =false;//Whether it is a white background//winmain Entry FunctionintApientry _tWinMain (hinstance hinstance, hinstance hprevinstance, LPTSTR lpCmdLine,intnCmdShow) {unreferenced_parameter (hprevinstance); Unreferenced_parameter (lpCmdLine);//Registration window class if(! Appregisterclass (hinstance)) {return(FALSE); }//Initialize the application window if(! InitInstance (HINSTANCE, ncmdshow)) {return FALSE; }//message loopMSG msg; while(GetMessage (&msg,NULL,0,0) {TranslateMessage (&msg); DispatchMessage (&MSG); }return(int) msg. WParam;}//Registration window classATOM Appregisterclass (hinstance hinstance) {wndclassex Wcex; Wcex. cbsize=sizeof(Wndclassex); Wcex. Style= Cs_hredraw | Cs_vredraw; Wcex. Lpfnwndproc= WndProc; Wcex. Cbclsextra=0; Wcex. Cbwndextra=0; Wcex. HInstance= HInstance; Wcex. Hicon= LoadIcon (NULL, idi_application); Wcex. Hcursor= LoadCursor (NULL, Idc_arrow); Wcex. Hbrbackground= (Hbrush) (color_window+1); Wcex. Lpszmenuname=NULL; Wcex. lpszClassName= G_szwindowclass; Wcex. HICONSM=NULL;returnRegisterClassEx (&WCEX);}//Save the instantiation handle and create the main windowBOOLInitInstance (HInstance hinstance,intnCmdShow) {hInst = hinstance;//save handle to global variablesG_hwnd = CreateWindow (G_szwindowclass, G_sztitle, Ws_overlappedwindow,0,0, -, -,NULL,NULL, HINSTANCE,NULL);//Create buttonHWND Hbtwhite = CreateWindowEx (0, L"button", L"White", Ws_child | ws_visible | Bs_text, -, -, -, -, G_hwnd, (HMENU) Id_button_draw, HInst,NULL); HWND Hbtgray = CreateWindowEx (0, L"button", L"Grey", Ws_child | ws_visible | Bs_center, -, -, -, -, G_hwnd, (HMENU) Id_button_sweep, HInst,NULL);if(!g_hwnd) {return FALSE; } ShowWindow (G_hwnd, ncmdshow); UpdateWindow (G_hwnd);return TRUE;}//(window) Message processingLRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM WPARAM, LPARAM LPARAM) {intWmid, Wmevent; Paintstruct PS; HDC hdc;Switch(message) { CaseWm_command:wmid = LoWord (WParam);//wmevent = HiWord (WParam); Switch(Wmid) { CaseId_button_draw:onbuttonwhite (); Break; CaseId_button_sweep:onbuttongray (); Break;default:returnDefWindowProc (hWnd, message, WParam, LParam); } Break; CaseWM_PAINT:HDC = BeginPaint (hWnd, &ps); OnDraw (HDC); EndPaint (HWnd, &ps); Break; CaseWm_destroy:postquitmessage (0); Break;default:returnDefWindowProc (hWnd, message, WParam, LParam); }return 0;}//Event handling//Press the event when HbtwhitevoidOnbuttonwhite () {g_bwhite =true; InvalidateRect (G_hwnd,NULL,FALSE);//Refresh window}//Press the event when HbtgrayvoidOnbuttongray () {g_bwhite =false; InvalidateRect (G_hwnd,NULL,FALSE);//Refresh window}//Draw events (redraw the image each time the refresh is refreshed)voidOnDraw (hdc hdc) {point oldpoint; Setviewportorgex (HDC,0,0, &oldpoint); RECT Rcview; GetWindowRect (G_hwnd, &rcview);//Get the handle of the canvas sizeHbrush hbrwhite = (hbrush) getstockobject (White_brush); Hbrush Hbrgray = (hbrush) getstockobject (Gray_brush);if(G_bwhite) {FillRect (hdc, &rcview, hbrwhite); }Else{FillRect (hdc, &rcview, Hbrgray); } Setviewportorgex (hdc, Oldpoint. x, Oldpoint. Y,NULL);}
In the above example, the message flows through the following process:
Figure 3: The process of message flow
This is in line with the "message mechanism of programming ideas" in Figure 1 (Message mechanism principle) is consistent, this is the core part of Windows Messaging mechanism, is also the core of Windows API development.
Windows systems and programs under Windows are message-based and event-driven.
The role of RegisterClassEx is to register a window that must be registered with the Windows system to obtain a unique identity before calling CreateWindow to create a window.
while (GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); DispatchMessage(&msg);}
This while loop is a message loop that continuously fetches messages from the message queue and distributes the messages through DispatchMessage (&msg). Message Queuing is defined in the Windows operating system (we cannot see the code that corresponds to the definition), and for each executing Windows application, the system establishes a message queue, the application queue, that holds messages for various windows that the program may create. DispatchMessage will pass the message to the window function (that is, the message handler function) to deal with, that is, the WndProc function. WndProc is a callback function that is passed to the operating system through Wcex.lpfnwndproc when the window is registered, so the DispatchMessage distributes the message and the operating system calls the window function (WNDPROC) to process the message. For a callback function, refer to the callback function.
Each window should have a function responsible for message processing, and the programmer must be responsible for designing this so-called window function WndProc. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
the four parameters in the message are information about the messages (the handle of the message, the message type, and so on), and the functions are handled differently by switch/case according to the different message types. After receiving the corresponding type of message, the corresponding function can be called to deal with, such as Onbuttonwhite, Onbuttongray, OnDraw, which is the embryonic form of event processing. Invoking Defwindowproc,defwindowproc in default is the default message handler defined by the operating system, because all messages must be processed, and messages that the application does not process need to be handled by the operating system.
Definition and type of message
Windows messages are prefixed with wm_, meaning "windows message", such as Wm_create, WM_PAINT, and so on. The message is defined as follows:
typedef struct tagmsg{hwnd hwnd; //the window handle that accepts the message UINT message; //message constant identifier, which is what we usually call the message number WPARAM WPARAM; //32 bit message, the exact meaning depends on the message value LPARAM LPARAM; //32 bit message, the exact meaning depends on the message value DWORD time; //the time the message was created Point pt; //the position of the mouse/cursor in the screen coordinate system when the message was created } MSG;
There are three main types of messages:
1. Command Message (WM_COMMAND): Command message is a command that the programmer needs the program to do certain things. Any message generated by the UI object is such a command message, possibly from a menu, accelerator key, or toolbar button, and so on, in Wm_command.
2. Standard window message: In addition to WM_COMMAND, any message beginning with WM_ is this category. The standard window message is the most common message in the system, which refers to the messages used by the operating system and the windows that control other windows. For example, CreateWindow, DestroyWindow, and MoveWindow will fire window messages, as well as mouse movements, clicks, and keyboard input are all part of this message.
3. Notification: This message is generated by the control in order to notify its parent window (usually a dialog window) of a situation. When a child control inside a window has something that needs to be notified to the parent window, it is now on. The notification message applies only to standard window controls such as buttons, list boxes, combo boxes, edit boxes, and Windows common controls such as tree view, List view, and so on.
Queue messages and non-queue messages
There is a system message queue in Windows, and for each executing Windows application, the system establishes a message queue, the application queue, that holds messages for various windows that the program may create.
(1) Queue message (Queued Messages)
Messages are saved in the message queue, and messages are retrieved from the message queue through a message loop and distributed to the various window functions to process, such as a mouse, keyboard message belongs to this kind of message.
(2) Non-queue messages (nonqueued Messages)
Is that the message is sent directly to the window function processing without passing through the message queue. such as: Wm_activate, Wm_setfocus, Wm_setcursor, wm_windowposchanged belong to this category.
The difference between PostMessage and SendMessage
The message sent by PostMessage is a queue message that posts the message to the message queue, the message sent by SendMessage is not a queue message, is sent directly to the window process, and the message is processed before it is returned.
Figure 4: Message Queuing
To prove the process, we can change the example above.
1. Add the definition of id_button_test in Win32Test.h
#define ID_BUTTON_TEST 1002
2. Send messages in Onbuttonwhite with SendMessage and PostMessage respectively
Events when Hbtwhite is pressed
void OnButtonWhite(){ true; NULLFALSE); //刷新窗口 0); //PostMessage(g_hWnd, WM_COMMAND, ID_BUTTON_TEST, 0);}
3. Add Id_button_test judgment to the message loop
whileNULL00)) { if (LOWORD(msg.wParam) == ID_BUTTON_TEST) { OutputDebugString(L"This is a ID_BUTTON_TEST message."); // [BreakPoint1] } TranslateMessage(&msg); DispatchMessage(&msg); }
4. Increase id_button_test judgment in window processing function WndProc
case ID_BUTTON_TEST: { OutputDebugString(L"This is a ID_BUTTON_TEST message."); // [BreakPoint2] } break;case ID_BUTTON_DRAW: OnButtonWhite(); break;case ID_BUTTON_SWEEP: OnButtonGray(); break;
Debugging with breakpoints we found that the Id_button_test message sent with SendMessage will only go into BreakPoint2, and postmessage send the Id_button_ Test will go into BreakPoint1 and BreakPoint2.
If you have any doubts and ideas, please give feedback in the comments, your feedback is the best evaluator! Due to my limited skills and skills, if the Ben Boven have errors or shortcomings, please understand and give your valuable advice!
======================== programming thought series of articles review ========================
Message mechanism of programming thought
Logging of programming ideas
Abnormal handling of programming thought
The regular expression of programming thought
An iterative device for programming ideas
Recursion of programming thought
The callback of programming thought
Deep into the message mechanism in Windows kernel--c++