In-depth analysis of the MFC for Windows message processing, running mechanism

zhaozj2021-02-11  177

sequence:

I have an in-depth understanding of the Windows system, MFC, but I am very interested in the mechanism of the MFC itself, especially after reading the teacher's "deep shallow MFC", I feel very refined by Visual C Application Framework. [No Dare to use "perfect" one word]. Before, I have a certain understanding of the SDI structure processing message, but I don't know the message mechanism of the Mode dialog. I have not been solved by "in-depth" book. Recently, through the help of netizens on 9CBS, and check MSDN, self-conscious. For a while, write these texts, there is no other purpose, just hope that the later people will bent, and I hope to discuss and learn from those who like "Drill Celetum". If you are a cattle, then you should carefully consider there is anything sufficient to read these childish words [What does this? Please take a look at: http://www.9cbs.net/expert/topic/13/13451.xml related reviews]. In this article, some "theory" is my own guess, please refer to it. [The content of the article is a certain content repeated "in-depth" book.

text:

One of the main differences between Windows programs and DOS programs is that Windows programs are based on events, and the message mechanism is based. How to understand? For example, when you click Windows "Start" Button, do you pop up a menu? When you click the left mouse button, the driver associated with the mouse in the operating system receives this signal [lbuttondown] in the first time, then it notifies the operating system - "Hey, the left button is clicked!" After the operating system gets this signal, it is necessary to judge - the user clicks the left mouse button. Which window is this? How to determine? this is very simple! In the current state, the window with focus is [or control] is [here is of course "Button]. Then the operating system immediately sends a message to this window to the message queue where the process is located, the message content should be the code of the message itself, additional parameters, window handle ... and more. So, do only the operating system is eligible to send a message to a message to a window? Otherwise, other procedures are also qualified. You can call in your program: SendMessage, PostMessage. In this way, the clicked window gets a message containing Click, the operating system has not been tuned anything to the window because it is also busy with other transactions. How do your program get a message? Windows makes the following reflection for you on the "Start" Button: pop up a menu. However, how is the message to make this process is achieved? This is the main content discussed in this article [of course just for MFC]. I first briefly talk about SDI, then spend more text description mode dialog box. For SDI window, your application class of the InitInstance () approximately 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 cmdInfo; ParseCommandLine (cmdInfo); if (ProcessShellCommand (cmdInfo!)) return FALSE; m_pMainWnd-> ShowWindow (SW_SHOW); m_pMainWnd-> UpdateWindow () Return True;} Complete work such as dynamically generated document, depending on, display the main frame window, processing parameter row information, etc. These are "clear" displayed in your project. We now set the breakpoint to return true; one sentence, follow the MFC source code, see what is done inside the bottom MFC. The program enters SRC / WinMain.cpp, the next big action should be: nreturNCode = pthread-> run (); everyone's attention is concerned, focusing.

F11 Enter 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 ();} Re-enter: 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 received for (;;) {// phase1: check to see if we can do idle work while (bIdle && :: PeekMessage (& m_msgCur, NULL, NULL, NULL, PM_NOREMOVE! )) {// call onidle while in bidle statiff (! 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) {bidle = true; lidlevount = 0;}

} While (:: PeekMessage (& M_Msgcur, Null, Null, Null, PM_NOREMOVE));

Assert (false); // not reachable}

BOOL CWinThread :: IsIdleMessage (MSG * pMsg) {// Return FALSE if the message just dispatched should _not_ // cause OnIdle to be run. Messages which do not usually // affect the state of the user interface and happen very // often Are Checked for.

// 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_systimer (Caret Blink) Return PMSG-> Message! = WM_Paint && Pmsg-> Message! = 0x0118;} This is the central organization of SDI processing messages, but please note that it is not the core! Analysis, a While Cycle While (Bidle &&fur, Null, Null, NULL, PM_NOREMOVE)) {// call onidle while (! " Bidle = false; // Assume "No IDle" State} This code is when there is no message in your program process, you call OnIdle to do some backup work, temporary objects are deleted here. Of course it is a virtual function. The peekMessage is a view of the message queue. If there is a message returns true, if there is no message returning false, specify PM_NOREMOVE here, it means that the news that is not moved in the message queue is just viewed, which means that the peekmessage only To a detection, obviously return false [即 no message] will enter the interior of the loop, execute onder, of course, your OnIdle returns Flase, let the program no longer execute OnIdle. You may have to ask: Where is the program executing when there is a message in a bidlfele = 0 or message team? Do {// pump message, but quit on wm_quit if (! pumpMessage ()) Return exitInstance ();

// reset "no idle" state after pumping "normal" message if (isidleMessage) {bidle = true; lidlevount = 0;}

} While (:: PepMessage (& M_Msgcur, Null, Null, Null, PM_NOREMOVE));

Look, enter a loop again! One of these important functions, the PumpMessage, the content is as follows: BOOL CWINTHREAD :: PUMPMESSAGE () {Assert_Valid (this);

if (:: GetMessage (& m_msgCur, NULL, NULL, 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 f (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 think, this is the core base MFC message processing [ It is also my personal thinking]. GetMessage is different from PeekMessae, it does not have a message, and PeekMessage will return 0 if there is no message in the message queue, and getMessage If there is no message, wait until you have a message, and getMessage is different from peekmessage, it will Message removal [Of course, PeekMessage can also do this]. I want to read this function after you read this function, you should use the usage of the PretranslateMessage function [I prefer to take advantage of this function in the program]. :: TranslateMessage ;: DispatchMessage; Send the message to the window to the window [specified by the window class], the subsequent action has been reflected by your program, you can be " Deeply "a perfect explanation. We still pass the reurn true; return to the do {} while; loop in Cwinthread :: Run (). Then I still handled my IDLE, even if your OnIdle returns false, here you see, your program still has a chance to perform it. Then use the PeekMessage Detect Message Queue: If there is a message [this message is not moved reason is because it is useful for getMessage in the PumpMessage. ] Enter the PumpMessage [call it "message pump" again. If there is no message, exit the DO loop, but it is still inside for for, so performs the first While loop. This is an execution process of CWINTHREAD :: Run. Don't worry about it doesn't (;;) If you have a wm_quit in your message queue, you will return 0, then PumpMessage returns 0 and Run () inside: if (! PumpMessage ()) Return EXITINSTANCE () ;.

SDI said this, let me talk about the mode dialog box. I am discussed in 2 cases: When your project is based on the mode dialog box [no parent window, or for desktop]. The difference is that SDI inside InItInstance application classes: 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 by Dialog Is // Dismissed with Cancel} // Since The Dialog Has Been Closed Application, Rather Than Start The Application's Message Pump. Return false;} int nresponse = DLG.DOMODAL (); a sentence makes your entire program in Domodal () inside . Moreover, when you quit Domal () [You must end your dialog box], INITINSTANCE returns false, we know, this, cwinthread :: run is not performed. But where is the message processing? It turned out that DLG.Domodal () inside CWINTHREAD :: Runmodalloop, the role is the same as Run () [of course, there is small difference inside, please refer to MSDN] !!!

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

How is this working? It has built such a project as an example. SDI, handles lbuttondown: mydlg.domodal () in Vieww, with buttons in myDLG, with exhaustion.

No display mode dialog box, message processing has been made in cthread :: run (). After you click, the program execution point enters the runmodalloop inside Domodal (), which is another message processing mechanism. But Domodal () is called Runmodalloop, will drop its parent window. After coming out of RunmodallOop, you can enable it. Mode dialog and non-Mode dialog box are created by calling createDialogindirect (). Then it and the non-mode dialog box difference is What is caused? 1 Mode dialog off the parent window disable. I was thought that the disable window did not receive a message. But then I immediately found that I was wrong. But why you have Keyborad of the Disable window. When the MOUSE moves, the window does not reflect, I think this may be the ghost from the operating system. I started to send a message to the window in this article, I want to find the target window to process the Disabled status. When you send a message to it, but this cannot be said that the window does not receive messages, other programs [or it itself] is sent to it or can receive and process .2 Mode dialog, itself has a message processing mechanism RunmodalloP. The above is experimenting. I add a Button in the Mode dialog in my just built project, where is the following code: onbutton1 () {getpaR () -> enableWindow (1);} Click, after we It was found that it is no longer manifested as "modal", I tried to click on the menu, or it will make a normal reflection. I think this message [for the parent window, such as menu action] should also be in the mode Processing in Runmodalloop in the dialog box [I can't determine].

Write here first, a little turbidity. Please criticize it.

9cbs roast chicken wings 2002-4-24

转载请注明原文地址:https://www.9cbs.com/read-5761.html

New Post(0)