The procedures that once fought under the Win32 platform must remember how many sleepless nights to figure out the concept of a "message loop". Although we no longer need it in the process of writing application code today, it is still necessary to have a deep understanding of the message flow mechanism within the Windows platform.
In the early days of writing programs directly with the Win32/win16 API, the message loop was the first idea we had to understand. Now, whether you use a Windows application framework (MFC, VCL, VB,. NET framework), even Unix, Linux, macosx the application framework above , it's not easy to see the message loop. In fact, the message loop is still there, just wrapped up in these applicationframework, buried deep in a corner.
This article attempts to evoke memories of the message loop and attempts to explain how the message loop is encapsulated in the. NET Framework's Windows Forms. Although Windows Forms hides all this, it leaves a lot of room for us to handle WIN32 messages on our own.
a traditional Windows program
Traditional Windows programs, written only using the Win32 API, here is an example of a program, in order to save space, I will omit many of the program code:
Program Entry point
int Apientry _tWinMain (hinstance hinstance, HInstance hprevinstance,
LPTSTR lpcmdline, int ncmdshow) {
MSG msg;
if (! InitInstance (HINSTANCE, ncmdshow)) {
return FALSE;
}
Main message loop:
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&MSG); DispatchMessage (&MSG);
}
return (int) Msg.wparam;
}
Functions: WndProc (HWND, unsigned, WORD, LONG)
Purpose: Handles messages for the main window.
Lresult CALLBACK WndProc (
HWND hwnd, UINT message, WPARAM WPARAM, LPARAM LPARAM) {
int Wmid, wmevent; Paintstruct PS;
HDC HDC;
Switch (message) {
Case WM_COMMAND:
Wmid = LoWord (WParam);
Wmevent = HiWord (WParam);
Profiling Menu Pick Items:
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 program code here ...
EndPaint (HWnd, &ps);
Break
Case Wm_destroy:
PostQuitMessage (0);
Break
Default
Return DefWindowProc (HWnd, Message,wparam, LParam);
}
return 0;
}
The message processing routines for the [about] squares.
Lresult CALLBACK About (HWND hdlg, UINT message,
WPARAM WPARAM, LPARAM LPARAM) {
Switch (message) {
Case WM_INITDIALOG:
return TRUE;
Case WM_COMMAND:
if (LoWord (wParam) = = Idok | | LoWord (wParam) = = IDCANCEL) {
EndDialog (Hdlg, LoWord (WParam));
return TRUE;
}
Break
}
return FALSE;
}
1, from within the _tWinMain, the program enters the main message loop,
2, and the message loop obtains a message from Message Queuing (by calling GetMessage ()). Each executing program has a message queue of its own;
3, the message loop determines which Windows Procedure (WNDPROC) The message should be sent based on the message content, ... this is known as message distribution (Messages Dispatch). Typically, each window or control has a Windows Procedure that handles the behavior of that window/control,
4, and Windows Procedure determines which function to call based on the content of the message (using switch/ case syntax);
5, Windows procedure processing, control back to the message loop. Continue with Actions 2, 3, 4, 5,
6, when the message queue is empty, GetMessage () cannot get any messages, enters the idle (idle) state, and goes to sleep (instead of busy waiting). When the message queue is no longer empty, the program automatically wakes up and continues with 2, 3, 4, 5 actions;
7, when the message obtained is Wm_quit,getmessage (), the return value of 0 is obtained, leaving the message loop, and the program ends. The program uses the call PostQuitMessage () to place the Wm_quit in the message queue, which ends later rather than jumping out of the loop directly.
is named queues,.. However, messages in Message Queuing are not always FIFO (first-in-Out,fifo), with some exceptions:
. As long as there is wm_quit in the message queue, the wm_quit is removed first, Causes the program to end.
. Wm_paint and Wm_timer are removed only when there is no other news. and multiple WM_PAINT may be merged into one, and so is wm_timer.
. The use of TranslateMessage () to process messages can cause new messages to occur. For example: TranslateMessage () can identify the wm_keydown (press the key) plus Wm_keyup (press release) to produce WM_CHAR (character input).
What is a message
The mouse moves, the keys are pressed, the window is closed, and these all produce messages. In the Windows operating system, messages are present in the following data structure (defined in the WinUser.h file):..
typedef struct TAGMSG {
HWND hwnd;
UINT message;
WPARAM WPARAM;
LPARAM LPARAM;
DWORD time;
Point pt;
MSG;
There are six messages in the message, respectively:
. HWND: The number of the unique HWND of the window/control. The message loop sends the message to the correct destination based on this information.
. Message:windows the ID of the predefined message type.
. WParam and lparam: Some messages themselves need to carry more information, which is placed in WParam and lparam.
. Time and PT: The message occurred at times with the mouse position.
how the. NET Framework encapsulates message loops
The. NET Framework's Windows Forms encapsulates the message loop for our convenience. The classes (class) mentioned in this section belong to the System.Windows.Forms namespace (namespace).
A simple summary is as follows: The message loop is encapsulated in the run () static method of the Application class; Windows procedure is encapsulated in the NativeWindow and control classes; Individual message handling actions are encapsulated into the control The ONXYZ () of the class (for example, OnPaint ()). We can cover (override) onxyz () to provide our own program. can also be used. NET event mechanism, and on the XYZ event, add our event handler function (Handler). The ONXYZ () of the control class will actively invoke the handler function of the XYZ event.
Please note that because the event-handling functions of XYZ are called by the ONXYZ () method of the control class, when you overwrite the onxyz () method, do not forget to invoke the control class's ONXYZ () (unless you have special requirements), otherwise the XYZ event handler function will not work. Just call base. ONXYZ (), you can call the ONXYZ () method to the control class, as follows:
protected override void OnPaint (PaintEventArgs e) {
Base. OnPaint (e);/TODO: Join Form1.onpaint implementation
}
We can use the onxyz () of the Override control class to determine what to do when the message occurs. Similarly, we can even override the control and NativeWindow class WndProc () to define Windows Procedure.
Again, because the ONXYZ () series method is called by the Control class WndProc (), so when you overwrite WndProc (), do not forget to invoke the control class WndProc () (unless you have special needs), otherwise onxyz () Series methods (and the XYZ event handler function) will not work. Just call base. WndProc (), you can call WndProc () to the control class, as follows:
protected override void WndProc (ref message m) {
Base. WndProc (ref m);//todo: Join FORM1.WNDPROC implementation
}
As you may have noticed, WndProc () requires a parameter of the message class, which is the result of MSG being encapsulated as a. NET version.
An example of Windows Forms
To make the reader more aware of the actual situation, I use the example examples below to illustrate:
Namespace windowsapplication1{
A summary description of the Form1.
public class form1:form{
The variables required by the design tool.
Private Container components = null;
Public Form1 () {
AutoScaleBaseSize = new Size (5, 15);
ClientSize = new Size (292, 266);
Name = "Form1";
Text = "Form1";
Paint + = new Painteventhandler (this. Form1_paint);
Paint + = new Painteventhandler (this. FORM1_PAINT2);
}
The main entry point for the application.
[STAThread]
static void Main () {
Application.Run (New Form1 ());
}
protected override void OnPaint (PaintEventArgs e) {
Base. OnPaint (e); 2
}
private void Form1_paint (object sender, PaintEventArgs e) {
3
}
private void Form1_paint2 (object sender, PaintEventArgs e) {
4
}
protected override void WndProc (ref message m) {
Base. WndProc (ref m); 1
}
}
}
1. In main (), use Application.Run () to display the Form1 window and enter the message loop. During the execution of the program, Application.Run () has not been completed.
2, the OS in this process message queue in a WM_PAINT message, so that the window is displayed.
3, WM_PAINT is Application.Run () within the message loop out, distributed to WndProc (). Due to the polymorphic (polymorphism) factor, the call (Invoke) to the WndProc () is a Form1 WndProc (), where the annotation (comment) 1 in the above program is not invoked to Control.wndproc ( )。
4, at the end of Form1.wndproc (), there is a call to base. WndProc (), which is actually called to Control.wndproc ().
5, Control.wndproc () from the message parameter to learn that the messages are WM_PAINT, and then invoke OnPaint (). Due to polymorphic factors, this call to the OnPaint () is a Form1 of the OnPaint (), which is annotated 2 in the above program, rather than calling to Control.OnPaint ().
6, at the end of Form1.onpaint (), there is a call to base. OnPaint (), which is actually called to Control.OnPaint ().
7. We used to register Form1_paint () with Form1_paint2 () as the Paint event handler in the Form1 constructor (constructor)
(Event Handler). Control.OnPaint () will call the two functions in sequence, which is where annotations 3 and 4 are in the above program.
Why do you know so much? Thanks to the tools, now the programmer is very happy, can be in the paste of the case to write a program. However, such a programmer may not be competitive, after all, the component (component) drag-and-drop (drag and drop) to the screen, and then set the component properties of the work, not to say that there is too much difficulty. Only in-depth understanding of internal principles, to allow themselves to mastery of technology, but also to allow the programmer to walk more stable, longer.