MFC
Windows Message Processing
How the unit thread processes messages
The Message Processing Mechanism of Windows uses the following code for message processing:
MSG message;
While (: getmessage (& message, null, 0, 0 )){
: Translatemessage (& message );
: Dispatchmessage (& message );
}
When a message arrives, it is converted by translatemessage. For example, the wm_keydown message is converted to a wm_char message containing ASCII characters, and then sent by dispatchmessage, dispatchmessage returned.
Discard Control
In the waiting mode, dispatchmessage can be returned only after processing is completed. No message can be processed before this time. The following code can return immediately even if no message arrives in the program.
MSG message;
While (: peekmessage (& message, null, 0, 0, pm_remove )){
: Translatemessage (& message );
: Dispatchmessage (& message );
}
Timer
The timer does not depend on the CPU clock speed. note that windows is not a real-time operating system, so if the period you specify is less than 100 milliseconds, the cycle between timer events may be inaccurate.
With a timer, you can sometimes replace multithreading. For example, the following code allows you to still receive and process messages in a loop. this is a progress bar. You can change the display of the progress bar in ontimer and customize the Cancel message to terminate the program in oncancel.
Void cdlg: onstart ()
{
MSG message;
Settimer (0,100, null );
Getdlgitem (idc_start)-> enablewindow (false); // make the button invalid
Volatile int ntemp; // do not save the change in the register, because if the variable is saved in the register, a value error may occur during thread switching.
For (m_ncount = 0; m_ncount
For (ntemp = 0; ntemp <10000; ntemp ++ ){
.........
}
If (: peekmessage (& message, null, 0, 0, pm_remove )){
: Translatemessage (& message );
: Dispatchmessage (& message );
}
}
Cdlg: onok (); // closes the dialog box after the thread ends.
}
Multi-Thread Programming
A process is a running program that has its own memory, file handle, and other system resources. A single process can contain independent execution, called a thread.
Windows provides two types of threads: worker threads and user interface threads. User Interface threads usually have windows and have their own message loops. the worker thread has no window, so it does not need to process messages.
Compile thread functions and start threads
The thread body is generally in the form:
Uint threadproc (lpvoid pparam)
{
Return 0;
}
Start thread usage:
Cwinthread * pthread =
Afxbeginthread (threadproc, getsafehwnd (), thread_priority_normal );
How the main thread communicates with the working thread using global variables
Global variable communication is the simplest and most effective method.
For example, the following code:
Uint threadproc (lpvoid pparam)
{
G_ncount = 0;
While (g_ncount <100)
: Interlockedincrement (long *) & g_ncount );
Return 0;
}
The interlockincrement function blocks other threads from accessing the variable during variable addition 1. If you use: g_ncount ++ directly without using this function, an error may occur.
The worker thread communicates with the master thread to send messages.
The following code sends a message to the parent process after the thread is completed:
Uint threadproc (lpvoid pparam)
{
.........
: Postmessage (hwnd) pparam, wm_threadfinished, 0, 0 );
Return 0;
}
Use events for Thread Synchronization
The cevent class is an event class. It is in the "non-signal" state when it is just defined. You can call the setevent () member function to set it to "signal" state.
The following code: the thread first waits for the start signal. If the start signal is not set, the thread will be suspended and waiting for the end signal during running. If the end signal occurs, the thread will be terminated.
Cevent g_eventstart, g_eventkill;
Uint threadproc (lpvoid pparam)
{
// Infinite indicates waiting for unlimited time
: Waitforsingleobject (g_eventtart, infinite );
For (.........)
{
..........
If (: waitforsingleobject (g_eventkill, 0) = wait_object_0 ))
Break;
}
Return 0;
}
When the thread is started: g_eventstart.setevent ();
When the thread is terminated: g_eventkill.setevent ();
However, if the thread has not been started before it is terminated, the thread should be started before terminating it.
Note: If the thread is terminated abnormally, memory leakage may occur. For example, the thread is forcibly terminated by closing the process, or the Win32 terminatethread function is used.
Critical Section
The ccriticalsection class can be used to wrap the critical segment handle. For example:
Ccriticalsection g_cs;
G_cs.lock ();
G_ncount ++;
G_cs.unlock ();
User Interface thread
I
Generally, the user interface thread is used to obtain multiple top-level windows. For example, if you want to allow the user to run multiple instances of the program, but you want all instances to share the memory, IE is like this.
You can derive a class from cwinthread and start this thread using the overloaded version of afxbeginthread. The derived class has its own
The initinstance function has its own message loop.
Win32 SDK
Event usage
Handle g_hcloseevent = NULL;
G_hcloseevent = createevent (null, true, false, null );
If (g_hcloseevent = NULL)
Return false;
Set the signal: setevent (g_hcloseevent );
Thread Creation Method
The general form of the thread body:
DWORD winapi threadproc (lpvoid pparam)
{
Return 0;
}
At creation:
Handle hreceivethread = NULL;
Uint threadid;
Hsf-ethread =
Createthread (null, 0, threadproc, hwnd, 0, & threadid );
If (hsf-ethread = NULL)
Return false;
// The priority is normal.
Setthreadpriority (hsf-ethread, thread_priority_normal );
How to Use the critical section
Critical_section csrecvread = {0 };
Initializecriticalsection (& csrecvread); // initialize the critical section
Entercriticalsection (& csrecvread); // use the critical zone variable
Prightbuffer = prightbuffer + Len;
Leavecriticalsection (& csrecvread );
-----------------------------------------------------------
Thoughts on VC ++ message ing
Author: Hao Qingxin
Message ing is inevitable when learning VC ++. We all know that C ++ is an object-oriented programming language. Why does it implement message ing in VC ++?
First, you must understand how a Windows program that contains message processing works.
Generally, a Windows program that contains message processing must contain at least two functions.
First:
Int winapi winmain (
Hinstance, // handle to current instance
Hinstance hprevinstance, // handle to previous instance
Lpstr lpcmdline, // command line
Int ncmdshow // show state
);
Second:
Long Far Pascal wndproc (hwnd, word message, word wparam, long lparam );
We do not need to tangle the details of the program implementation. As long as we understand that the wndproc function must be registered in the first function winmain, winmain tells windows
System, listen, I know you want to produce a lot of messages. Here I have a wndproc function to process the various messages you pass. Of course, the message format is well defined by the system.
Second, we need to understand how polymorphism is achieved in C ++.
We know that the key to implementing polymorphism is late binding (or later binding). The essence is that the compiler does not specify the absolute address to call the function during compilation, instead, it specifies the offset address of the function within a class.
To implement the above functions, the compiler has made some effort for us.
1. In each class with a virtual function, the compiler secretly places a pointer called vpointer.
2. When the system is running, create a vtable for each class, which contains the virtual function address that can be called.
3. Start vpointer and point to vtable. The correct function address needs to be called is found by offset in vtable.
Then, the MFC encapsulates the window API.
When
When we use the MFC framework to develop programs, especially when developing interface applications, we must use cwnd or a class derived from cwnd. Based on the object-oriented design principles
Some common functions, such as window University changes (onsize) and window moving (onmove), should be declared as virtual functions in cwnd, and then reload them in the inherited class. However
Each related derived class must have a vpointer and a set of record vtable. The common functions in cwnd are so many, and many derived classes in cwnd are bound to cause the system
It is obviously inappropriate to use too much resources (memory) for running.
So how does MFC implement it?
The answer is to use as few virtual functions as possible in the cwnd base class, instead of message ing.
You can check the functions in the cwnd class to find this point.
Cwnd: onmove
Afx_msg void onmove (int x, int y );
The above function is not a virtual function.
The last question is how message ing is implemented?
In a word, the macro definition is used to implement process-oriented message processing.
For example, the following message ing macro is available in VC.
Begin_message_map (cmainframe, cframewnd) // {afx_msg_map (cmainframe)
On_wm_create ()
//} Afx_msg_map
On_command (id_font_dropdown, donothing)
End_message_map ()
After compilation, the code is replaced with the following form (this is only for explanation, but the actual situation is much more complicated than this ):
// Begin_message_map (cmainframe, cframewnd)
Cmainframe: newwndproc (...)
{
Switch (...)
{
// {Afx_msg_map (cmainframe)
// On_wm_create ()
Case (wm_create ):
Oncreate (...);
Break;
//} Afx_msg_map
// On_command (id_font_dropdown, donothing)
Case (wm_command ):
If (hiword (WP) = id_font_dropdown)
{
Donothing (...);
}
Break;
// End_message_map ()
}
}
In this way, VC ++ eliminates the need for some virtual functions, thus saving memory space.
References:
Thingking in C ++, Bruce Eckel;