Queue messages and non-queued messages From the sending path of the message, the message can be divided into two types: queue messages and non-queued messages. Message queues are divided into system messages and thread messages. The system message queue is maintained by Windows, and the thread message queue is maintained by each GUI thread. To avoid the creative message queue to the Non-GUI, there is no message queue when all threads generate, only the number of GDI functions only when the thread is first called for the first time The system creates a message queue for threads. The queue message is sent to the system message queue, then go to the thread message queue; the non-queue message is directly given to the destination window process.
For queue messages, the most common are messages triggered by mouse and keyboard, such as WM_Mousermove, WM_CHAR, etc., and some other messages, such as WM_PAINT, WM_TIMER, and WM_QUIT. When the mouse, the keyboard event is triggered, the corresponding mouse or keyboard driver converts these events into a corresponding message, then transports to the system message queue, and processes by the Windows system. The Windows system takes a message from the system message queue in the system message queue. According to the above MSG message structure determines the message to be sent to that window, then send the removed message to the corresponding queue of the thread of the creation window. The following things should be carried out by the thread message, and Windows starts to go to their own things. Threads have messages in their message queue, which is taken from the queue, and send it to the appropriate window process by the operating system.
In general, the system always puts the message POST at the end of the message queue. This ensures that the window accepts the message in advanced first. However, WM_PAINT is an exception, and multiple WM_PAINT of the same window is merged into a WM_PAINT message, merge all invalid areas to an invalid area. The purpose of combining WM_Pain is to reduce the number of refresh windows.
The non-queue message will bypass the system queue and message queue, and send the message to the window process directly. The system sends a non-queue message notification window, and the system sends a message notification window. For example, when a user activates a window system to send WM_Activate, WM_SETFOCUS, and WM_SETCURSOR. These messages notification windows are activated. Non-queued messages can also be generated by the application call system function. For example, when the program calls the SETWINDOWPOS system sends a WM_WINDOWPOSCHANGED message. Some functions also send non-queued messages, such as the function we have to talk about.
Message transmission
After understanding these basic theories above, we can make simple messaging and reception.
Send a message to the window: send, send, and broadcast.
Function sends a message there SendMessage, SendMessageCallback, SendNotifyMessage, SendMessageTimeout; function to send a message mainly PostMessage, PostThreadMessage, PostQuitMessage; I know the function of a broadcast message only BroadcastSystemMessage, BroadcastSystemMessageEx.
The prototype of SendMessage is as follows: LRESULT SendMessage (HWND HWND, UINT MSG, WPARAM WPARAM, LPARAM LPARAM), which is mainly to send a message to one or more windows, and will not return after the message is processed. However, it should be noted that if the window that receives the message is part of the same application, then the window function of this window is called immediately as a subroutine; if the window is received is created by another thread, then The window system switches to the corresponding thread and calls the corresponding window function, which is not placed in the target application queue. The return value of the function returns the window function of the window that receives the message, and the returned value depends on the message sent. The prototype of PostMessage is as follows: BOOL PostMessage (HWND HWND, UINT MSG, WPARAM WPARAM, LPARAM LPARAM), which places a message to the message queue of the thread that creates the HWND window, the function is not equal to the message and return to the control. . It should be noted that if the HWND parameter is hWnd_broadcast, then the message will be sent to all overlapping windows and pop-up windows in the system, but the sub-window does not receive the message; if the HWND parameter is null, the function is similar The PostthreadMessage function is called to call the DWTHREADID parameter to the current thread.
From the above two have a representative function, we can see that the communication method of the message and the difference of the sending method are located: Whether the message sent will be processed immediately, whether the function returns immediately. The message sent will be processed immediately. After processing, the function will return; sent by the message will not be handled immediately, he is put in a first-out queue, waiting for the application airline Has been processed, but immediately returns immediately after the function is placed.
In fact, there is no difference between sending messages to a window processing process and direct calling window processing procedures, their only difference is that you can ask the operating system to intercept all sent messages, but cannot intercept the window Direct calls for processing processes.
The message sent by the delivery method is usually corresponding to the user input event, because these events are not very urgent, can perform slow buffering processing, such as a mouse, the keyboard message is sent, and the button such as the button will be sent.
Broadcast messages are used, the BroadcastsystemMessage function prototype is as follows:
Long BroadcastsystemMessage (DWORD DWFLAGS, LPDWORD LPDWRECIPIENTS, UINT UIMESSAGE, WPARAM WPARAM, LPARAM LPARAM); This function can send a message to the specified recipient, which can be an application, an installable driver, network driver, system Level device driver messages and any combination of them. It should be noted that if the dwflags parameter is BSF_QUERY and at least one recipient returns Broadcast_Query_deny, the return value is 0, and if the BSF_Query is not specified, the function sends the message to all recipients and ignores its return value.
There are 3 functions for receiving messages for messages: getMessage, PeekMessage, WaitMessage. The GetMessage prototype is as follows: BOOL getMessage (LPMSG LPMSG, HWND, UINT WMSGFILTERMIN, UINT WMSGFILTERMAX); This function is used to obtain messages within the message value range given by the window specified by the HWND parameter and the WMSGFiltermin and WMSGFiltermax parameters. It should be noted that if hwnd is null, getMessage gets messages belonging to either window of calling the function application. If WMSGFILTERMIN and WMSGFILTERMAX are 0, GetMessage returns all available messages. After the function is acquired, other messages except the WM_Paint message except the WM_PAINT message will be deleted after the function is acquired. As for WM_PAINT, it is only deleted after it is handled. The PeekMessage prototype is as follows: BOOL PeekMessage (LPMSG LPMSG, HWND HWND, UINT WMSGFILTERMIN, UINT WREMOVELTERMAX, UINT WREMOVEMSG); This function is used to view the application's message queue. If there is any message, put it in the structure referred to in LPMSG, However, different from getMessage is that the PeekMessage function will not wait until the message is placed in the queue. Similarly, if hwnd is null, PeekMessage gets a message belonging to either window of the function application. If hwnd = -1, then the function returns a message sent to the PostappMessage function that causes the hWnd parameter to null. If WMSGFILTERMIN and WMSGFILTERMAX are 0, PEEKMESSAGE returns all available messages. After the function is acquired, other messages except the WM_Paint message except the WM_PAINT message will be deleted after the function is acquired. As for WM_PAINT, it is only deleted after it is handled. The WaitMessage prototype is as follows: BOOL VAITMESSAGE (); When an application can do, the function hands the control right to another application, while the application hangs until a new message is placed in the application. The queue is returned. The process of the message will follow us to talk about the processing of the message. First let's take a look at the message pump in the VC: while (GetMessage (& MSG, NULL, 0, 0)) {if (! TranslateAccelerator (msg.hwnd, HaccelTable, & MSG) ) {TranslateMessage (& MSG); DispatchMessage (& MSG);}}
First, getMessage gets a message from the message queue of the program's main thread and copies it to the MSG structure. If there is no message in the queue, the getMessage function will wait for a message to return. If you pass a window handle as the second parameter, then only the message with the specified window can be obtained from the queue. GetMessage can also filter messages from the message queue only accept messages in the message queue. At this time, you should use GetMessage / PeekMessage to specify a message filter. This filter is the range of a message identifier or a form handle, or both at the same time. It is useful when the application is looking for a subsequent message queue. WM_KEYFIRST and WM_KEYLAST constants are used to accept all keyboard messages. WM_MouseFirst and WM_MouseLast constants are used to accept all mouse messages. Then TranslateAccelerator determines whether the message is not a button message and is an accelerator message. If yes, the function will convert several buttons to an acceleration key message to pass to the window of the callback function. After processing the accelerator, the function translateMessage will convert two buttons WM_KEYDOWN and WM_KEYUP into a WM_CHAR, but it is necessary to pay attention to the message WM_KeyDown, WM_KEYUP will still pass the callback function of the window. After processing, the DISPATCHMESSAGE function will send this message to the set of callback functions in the window specified by the message. If the message is WM_QUIT, getMessage returns 0 to exit the cyclic body. Applications can use postquitMessage to end their own message loops. Usually call in the WM_DESTROY message of the main window. Let's take a common small example to illustrate the use of this message pump: if (: PeekMessage (& MSG, M_HWND, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) {if (msg.Message == WM_KEYDOWN && Msg.wParam == vk_escape) . . . } Here we accept all keyboard messages, so use WM_KEYFIRST and WM_KEYLAST as parameters. The last parameter can be PM_NOREMOVE or PM_REMOVE, indicating whether message information should be removed from the message queue. So this small code is to determine if the ESC key is pressed, if it is processed. Window Process Window Process is a function for processing all messages sent to this window. Any window class has a window process. The same class window uses the same window process to respond to the message. The system sends a message to the window process to pass the message data as a parameter to him. After the message arrives, according to the message type, the parameters are used to distinguish different messages, and the window procedure uses the parameters to generate appropriate behavior. One window process does not ignore the message if he does not process, it will pass the message to the execution of the default. The window process does this by calling DEFWINDOWPROC. The window process must return a value as its message processing result. Most windows only handle small parties and passing other DEFWINDOWPROCs to the system to do default processing. The window process is shared by all window belonging to the same class, and the message can be processed for different windows. Let's take a look at the specific example:
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; TCHAR szHello [MAX_LOADSTRING]; LoadString (hInst, IDS_HELLO, szHello, MAX_LOADSTRING); switch (message) { case WM_COMMAND: wmId = LOWORD (wParam); wmEvent = HIWORD (wParam); // Parse the menu selections: switch (wmId) {case IDM_about: DialogBox (hInst, (LPCTSTR) IDD_ABOUTBOX, hWnd, (DLGPROC) About); break Case IDM_EXIT: DESTROYWINDOW (HWND); Break; Default: Return DEFWINDOWPROC (HWND, Message, WParam, LParam);} Break
Case WM_Paint: HDC = Beginpaint (HWND, & PS); // Todo: Add any Drawing code Here ... Rect RT; GetClientRect (HWND, & RT); DrawText (HDC, Szhello, Strlen (Szhello), & RT, DT_CENTER; Endpaint (hwnd, & ps); Break;
Case WM_DESTROY: PostquitMessage (0); Break; Default: Return DefWindowProc (Hwnd, Message, WPARAM, LPARAM);} return 0;