In-depth analysis of WINDOWS Message Processing Mechanism in MFC

Source: Internet
Author: User

 

 

In-depth analysis of WINDOWS Message Processing Mechanism in MFC

 

I do not have a deep understanding of windows and MFC, but I am very interested in the mechanism of MFC packaging API, especially after reading "let's get started with MFC, I feel that the application framework of Visual C ++ is very refined. In the past, I had some knowledge about the message processing mechanism of the SDI structure, but I did not know about the message mechanism of the mode dialog box. I have not been able to solve this problem after reading the in-depth book. Recently, I think I have learned about it through the help of netizens and reading msdn. At the rise of the moment, writing these words has no other purpose. I just hope that the latencies will be avoided, and I also hope that people who like me will share the opportunity to discuss and learn. If you are a cool man, you need to carefully consider whether you have enough time to read these childish texts.

Body:

One of the main differences between Windows programs and DOS programs is that Windows programs are based on event-driven and message mechanisms. How to Understand?

For example, why does a menu pop up when you click "start" button in windows?

When you click the left mouse button, the mouse-related driver in the operating system gets this signal [lbuttondown] immediately, and then it notifies the operating system-"Hi, the left mouse button is clicked! ", After the operating system receives this signal, it will be determined immediately-which window does the user target when the user clicks the left mouse button? How to judge? This is simple! In the current status, the window with focus [or control] is [this is of course the "Start" button]. Then the operating system immediately sends a message to the window to the Message Queue of the process in which the window is located. The message content should be the message code, additional parameters, window handle... Wait. Is only the operating system eligible to send messages to a message queue in a window? Otherwise, other programs are eligible. You can call sendmessage and postmessage in your program. In this way, the clicked window gets a message containing the click sent by the operating system. The operating system no longer cares about the window because it is busy with other transactions. What should you do after your program gets a message? Windows displays the following information about the click event on the Start button: A menu is displayed. However, how is the process of getting a message to reflect it? This is the main content discussed in this article [of course only for MFC].

First, let me briefly talk about SDI, and then I will spend more on the text description mode dialog box.

For the SDI window, the initinstance () of your application class is about as follows:

Bool cex06aapp: initinstance ()
{
...............
Csingledoctemplate * pdoctemplate;
Pdoctemplate = new csingledoctemplate (
Idr_mainframe,
Runtime_class (cex06adoc ),
Runtime_class (cmainframe), // main SDI frame window
Runtime_class (cex06aview ));
Adddoctemplate (pdoctemplate );
Ccommandlineinfo using info;
Parsecommandline (partition info );
If (! Processshellcommand (cmdinfo ))
Return false;
M_pmainwnd-> showwindow (sw_show );
M_pmainwnd-> updatewindow ();
Return true;
}

Complete some work, such as dynamically generating relevant documents and views, displaying the main frame window, and processing parameter line information. These are all "Clear codes" displayed in your project ". Now let's set the breakpoint to return true; a sentence, followed by the source code of the MFC to see what has been done inside the MFC.

The program enters src/winmain. cpp. the next major action should be:

Nreturncode = pthread-> Run ();

Note that the focus is on. Enter F11

Int cwinapp: Run ()
{
If (m_pmainwnd = NULL & afxolegetuserctrl ())
{
// Not launched/embedding or/automation, but has no main window!
Trace0 ("Warning: m_pmainwnd is null in cwinapp: Run-quitting application./N ");
Afxpostquitmessage (0 );
}
Return cwinthread: Run ();
}

Enter again F11:

Int cwinthread: Run ()
{
Assert_valid (this );

// For tracking the idle time state
Bool bidle = true;
Long lidlecount = 0;

// Acquire and dispatch messages until a wm_quit message is wrongly ed.
For (;;)
{
// Phase1: Check to see if we can do Idle Work
While (bidle &&! : Peekmessage (& m_msgcur, null, pm_noremove ))
{
// Call onidle while in bidle state
If (! Onidle (lidlecount ++ ))
Bidle = false; // assume "no idle" state
}

// Phase2: pump messages while available
Do
{
// Pump message, but quit on wm_quit
If (! Pumpmessage ())
Return exitinstance ();

// RESET "no idle" state after pumping "normal" Message
If (isidlemessage (& m_msgcur ))
{
Bidle = true;
Lelecount = 0;
}

} While (: peekmessage (& m_msgcur, null, pm_noremove ));
}

Assert (false); // not reachable
}

Bool cwinthread: isidlemessage (MSG * PMSG)
{
// Return false if the message just dispatched shold _ not _
// Cause onidle to be run. messages which do not usually
// Affect the state of the user interface and happen very
// Often are checked.

// Redundant wm_mousemove and wm_ncmousemove
If (PMSG-> message = wm_mousemove | PMSG-> message = wm_ncmousemove)
{
// Mouse move at same position as last mouse move?
If (m_ptcursorlast = PMSG-> PT & PMSG-> message = m_nmsglast)
Return false;

M_ptcursorlast = PMSG-> pt; // remember for next time
M_nmsglast = PMSG-> message;
Return true;
}

// Wm_paint and wm_#imer (caret blink)
Return PMSG-> message! = Wm_paint & PMSG-> message! = 0x0118;
}

This is the central mechanism for SDI to process messages, but note that it is not the core!

After analysis, a while loop occurs inside the infinite loop.

While (bidle &&
! : Peekmessage (& m_msgcur, null, pm_noremove ))
{
// Call onidle while in bidle state
If (! Onidle (lidlecount ++ ))
Bidle = false; // assume "no idle" state
}

This Code calls onidle to do some backup work when there is no message in the message queue of your program process. The temporary object is deleted here. Of course, it is a virtual function. Here, peekmessage is used to view the message queue. If a message is returned, true is returned. If no message is returned, false is returned, after the message is viewed, it does not remove the message that has just been viewed in the message queue. That is to say, the peekmessage serves only one detection function. Obviously, when false is returned, [no message] is returned. will enter the loop and execute onidle. Of course, if your onidle returns flase, the program will no longer execute onidle. You may want to ask:
When bidle = 0 or there is a message in the message team instance, where does the program run?

Do
{
// Pump message, but quit on wm_quit
If (! Pumpmessage ())
Return exitinstance ();

// RESET "no idle" state after pumping "normal" Message
If (isidlemessage (& m_msgcur ))
{
Bidle = true;
Lelecount = 0;
}

} While (: peekmessage (& m_msgcur, null, pm_noremove ));

Look, there is another cycle!

There is an important function, pumpmessage. The content is as follows:

Bool cwinthread: pumpmessage ()
{
Assert_valid (this );

If (! : Getmessage (& m_msgcur, null ))
{
# Ifdef _ debug
If (afxtraceflags & traceappmsg)
Trace0 ("cwinthread: pumpmessage-received wm_quit./N ");
M_ndisablepumpcount ++; // application must die
// Note: prevents calling message loop things in 'exitinstance'
// Will never be decremented
# Endif
Return false;
}

# Ifdef _ debug
If (m_ndisablepumpcount! = 0)
{
Trace0 ("error: cwinthread: pumpmessage called when not permitted./N ");
Assert (false );
}
# Endif

# Ifdef _ debug
If (afxtraceflags & traceappmsg)
_ Afxtracemsg (_ T ("pumpmessage"), & m_msgcur );
# Endif

// Process this message

If (m_msgcur.message! = Wm_kickidle &&! Pretranslatemessage (& m_msgcur ))
{
: Translatemessage (& m_msgcur );
: Dispatchmessage (& m_msgcur );
}
Return true;
}

As you may think, this is the core base of MFC message processing [I personally think].

Getmessage is different from peekmessae in that it does not get the message body. If peekmessage finds no message in the message queue, it returns 0, and if getmessage finds no message, wait until there is a message, besides, getmessage is different from peekmessage. It will remove the message [of course, peekmessage can also do this]. I think after you read this function, you should understand the usage of the pretranslatemessage function. [I prefer to make full use of this function in the program].

: Translatemessage (& m_msgcur );
: Dispatchmessage (& m_msgcur );

The processing function that sends a message to the window [it is specified by the window class], and the subsequent actions will be reflected by your program, you can get a perfect explanation in deep. We still return to do {} while; loop in cwinthread: Run () through reurn true. Then we still process the idle. Even if your onidle returns false, here you can see that your program still has the opportunity to execute it. Then peekmessage is used to detect Message Queues:

If there is a message [this message is not moved because it is used by the getmessage in the pumpmessage.] Go to pumpmessage again [call it "message pump"].

If there is no message, exit the do loop, but it is still inside the for, so the first while loop is executed.

This is an execution process of cwinthread: Run.

Don't worry about not returning for (;) If your message queue contains a wm_quit, it will make getmessage return 0, then pumpmessage returns 0 and run () Internal:

If (! Pumpmessage ())
Return exitinstance ();

This Is What sdi says. Let's talk about the mode dialog box. I will discuss it in two cases:

1. When your project is based on a mode dialog box, [no parent window or desktop].

Unlike SDI, it is in the initinstance of the application class:

Bool ccomboboxapp: initinstance ()
{
Afxenablecontrolcontainer ();
// Standard Initialization
// If you are not using these features and wish to reduce the size
// Of your final executable, you should remove from the following
// The specific initialization routines you do not need.
# Ifdef _ afxdll
Enable3dcontrols (); // call this when using MFC in a shared DLL
# Else
Enable3dcontrolsstatic (); // call this when linking to MFC statically
# Endif
This-> m_ncmdshow = sw_hide;
Ccomboboxdlg DLG;
M_pmainwnd = & DLG;
Int nresponse = DLG. domodal ();
If (nresponse = idok)
{
// Todo: Place code here to handle when the dialog is
// Dismissed with OK
}
Else if (nresponse = idcancel)
{
// Todo: Place code here to handle when the dialog is
// Dismissed with cancel
}
// Since the dialog has been closed, return false so that we exit
// Application, rather than start the application's message pump.
Return false;
}

Int nresponse = DLG. domodal (); make sure your entire program is in domodal. Besides, when you exit domal (), [you must have ended your dialog box] And initinstance returns false. We know that cwinthread: run will not be executed.

But where does the dialog box program process messages.

Originally, DLG. domodal () calls cwinthread: runmodalloop internally. It serves the same purpose as run () [of course, there are minor differences within it. Please refer to msdn]!

In the second case, you call DLG. domodal () in the SDI [or other] program to generate a mode dialog box [with a parent window].

How does this work?

This project is created as an example.

SDI, processing lbuttondown in view:

Mydlg. domodal ();

A button exists in mydlg and is used after being renewed.

Before the displayed mode dialog box is displayed, message processing is always performed in cthread: Run.

After you click, the program execution point enters the domodal () Internal runmodalloop, which is a message processing mechanism.

However, when runmodalloop is called in domodal (), its parent window will be disable. After runmodalloop is called, enable it.

The Mode dialog box and the non-mode dialog box are created by calling createdialogindirect (). What is the difference between the mode dialog box and the non-mode dialog box?

The 1 mode dialog box disable the parent window.

I thought the disable window would not receive messages. but then I immediately found out that I was wrong. however, when you perform keyborad and mouse actions on the disable window, the window does not reflect it. I think this may be a ghost from the operating system. at the beginning of this article, I wrote out the process of sending messages from the operating system to the window. I think it will not send messages to the window when it finds that the target window is processing the disabled status, however, this does not mean that the window does not receive messages. The messages sent to it by other programs [or itself] can still be received and processed.

The 2-mode dialog box contains the Message Processing Mechanism runmodalloop.

Experiment with the above two points.

Add a button in the mode dialog box of the project I just created, and add the following code:

Onbutton1 ()
{
Getparaent ()-> enablewindow (1 );
}

After clicking it, we found that it is no longer displayed as a "Modal". I tried to click the menu and it will still reflect it normally.

I think the processing of this message [for the parent window, such as menu action] should also be done in runmodalloop in the mode dialog box [I am not sure about this].

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.