Analysis of MFC (7) Call timing of CWND type virtual functions, default implementation

zhaozj2021-02-08  251

CWND class virtual function call timing, default implementation

FMD (http://www.fmdstudio.net)

CREATE

2. PrecreateWindow

3. PRESUBCLASSWINDOW

4. PretranslateMessage

5. WindowProc

6. Oncommand

7. ONNOTIFY

8. OnChildNotify

9. DefWindowProc

10. DESTROYWINDOW

11. PostncDestroy

CWND as a class that deals the most basic and window in the MFC, completed most of the window management tasks. At the same time, there is a lot of virtual functions, which provide interfaces for derived class participation in appropriate places.

It has always been confused with these virtual functions, and cannot be clearly determined when they call and have done it. Which is to pay attention to when heavy load ... etc.

Look at the original code of the MFC and want to see it.

Summarized as follows:

CREATE

Virtual Bool Create (LPCTSTR LPSZCLASSNAME, LPCTSTSTYLE, CONST Rect, CWnd * PparentWnd, Uint Nid, ccreatecontext * pContext = NULL);

Call the timing:

When the window is established

As the main window, most of them will directly or indirectly call CREATE in InitInstance ().

As the sub-window, most of the parent window is established, and the WM_CREATE message is issued, and the oncreate () is transferred to the onCreate ().

Features:

Control establishment details

CWND implementation:

.......

// Register the window class, call the API established window

// Allow Modification of Several Common Create Parameters

Createstruct CS;

cs.dwexstyle = dwexstyle;

Cs.lpszclass = lpszclassname;

cs.lpszname = lpszwindowname;

CS.Style = DWStyle;

cs.x = x;

CS.Y = Y;

Cs.cx = nwidth;

cs.cy = nheight;

cs.hwndparent = hwndparent;

cs.hmenu = Nidorhmenu;

Cs.hinstance = AfxgetInstanceHandle ();

cs.lpcreateparams = lpparam;

/ / Call the virtual function precreateWindow here, allowing "tampering" to establish parameters before actual establishment.

IF (! PrecreateWindow (CS))

{

Postncdestroy ();

Return False;

}

AfxhookWindowCreate (this);

HWND HWND = :: CreateWindowex (cs.dwexstyle, cs.lpszclass,

Cs.lpszname, cs.style, cs.x, cs.y, cs.cx, cs.cy,

Cs.hwndparent, cs.hmenu, cs.hinstance, cs.lpcreateparams;

#ifdef _Debug

IF (hwnd == null)

{

TRACE1 ("Warning: Window Creation Failed: getLastError Returns 0x% 8.8x / N",

GetLastError ());

}

#ENDIF

If (! AfXunhookWindowcreate ()) Postncdestroy (); // Cleanup if CreateWindowEx Fails Too Soon

IF (hwnd == null)

Return False;

AskERT (hwnd == m_hwnd); // shop Have Been Set in Send MSG Hook

Return True;

}

2. PrecreateWindow

Call the timing:

See the previous paragraph, in Create (), after setting the window to establish a data CS, before actual establishment, "expose" to the derived class, allowing the derived class to change the window to establish parameters.

Features:

Control creation parameters (in CREATE () can set the creation information, but create is sometimes implied by the frame structure, so when PrecreateWindow, then provide a chance to establish parameters for the revision window).

CWND implementation:

BOOL CWND :: PrecreateWindow (CreateStruct & Cs)

{

// If the user does not customize the class name in the derived class, the window class name is not set, using the MFC default registration class

IF (cs.lpszclass == null)

{

// make Sure The Default Window Class Is Registered

Verify (AFXDEFERREGISTERCLASS (AFX_WND_REG));

// no wndclass provided - Use child window default

Assert (cs.style & ws_child);

Cs.lpszclass = _afxwnd;

}

Return True;

}

If you need, use a custom window class, you should register in the PrecreateWindow of the derived class and get and specify the class name.

3. PRESUBCLASSWINDOW

Call the timing:

Create a window while attaching C WND objects on the window

CWnd :: Create ():

...

AfxhookWindowCreate (this);

HWND HWND = :: CreateWindowex (cs.dwexstyle, cs.lpszclass,

Cs.lpszname, cs.style, cs.x, cs.y, cs.cx, cs.cy,

Cs.hwndparent, cs.hmenu, cs.hinstance, cs.lpcreateparams;

AfxunhookWindowCreate ();

...

When the window is created, the system establishes the WH_CBT (Training) hook (intercept window action), complete the "package" of the CWND object to the window in the hook function.

File: // Many operation, mainly

// pWndinit is incoming parameters, it should be the CWND object pointer

// Object Connect to Window Handle

PWndinit-> attach (hwnd);

...

// Call the virtual function PRESUBCLASSWINDOW to give the user a chance to define the relevant operation, for example, the attachment of the child control

PWNDINIT-> PRESUBCLASSWINDOW ();

...

/ / Set message processing function, etc..

WndProc * PoldWndProc = PWNDINIT-> GetsuperWndProcAddr ();

...

WndProc AfxWndProc = AFXGETAFXWNDPROC ();

OldWndProc = (WndProc) setWindowlong (hwnd, gwl_wndproc,

(DWORD) AFXWNDPROC); ...

CWND implementation:

In the CWND class, there is no default action in this virtual function.

4. PretranslateMessage

Call the timing:

In the message queue processing loop of the process, the CWINAPP virtual function PretranslateMessage will be called before the message processing function of the window to the window, allowing the re-window to derive class to process the messages that will be transmitted.

CWINAPP :: PretranslateMessage will have PretranslateMessage that can be called to the window.

Let's first look at the following cwinthread :: PumpMessage's distribution process

...

:: GetMessage (& m_msgcur, null, null, null)

...

// cwinthread's PretranslateMessage virtual function is called

IF (M_Msgcur.Message! = WM_KICKIDLE &&! PretranslateMessage (& M_MSGCUR))

{

:: TranslateMessage (& M_MSGCur);

:: DISPATCHMESSAGE (& M_MSGCUR);

}

BOOL CWINTHREAD :: PretranslateMessage (MSG * PMSG)

{

....

CWND * PMainWnd = AFXGETMAINWND ();

// Call PretranslateMessage ();

/ / See the WalkpretranslateTree original code below

IF (cwnd :: walkpretranslatettetree (pmainwnd-> getsafehwnd (), pmsg))

Return True;

// in Case of Modeless Dialogs, Last Chance Route Through Main

// WINDOW's Accelerator Table

IF (PMainWnd! = NULL)

{

CWND * PWND = CWND :: fromHandle (PMSG-> hwnd);

IF (PWND-> getTopy ()! = PMainWnd)

Return PMainWnd-> PretranslateMessage (PMSG);

}

Return False; // no special processing

}

Bool Pascal CWnd :: Walkpretranslatetree (HWND HWNDSTOP, MSG * PMSG)

{

....

// call PretranslateMessage at all levels of windows

For (hwnd hwnd = pmsg-> hwnd; hwnd! = null; hwnd = :: getParent (hwnd))

{

CWND * PWND = CWND :: fromHandlepermanent (hwnd);

IF (PWND! = null)

{

IF (PWND-> PretranslateMessage (PMSG))

Return true; // trapped by target window (eg: accelerators)

}

// got to hwndstop window without intend

IF (hwnd == hwndstop)

Break;

}

Return False; // no special processing

}

5. WindowProc

Call the timing:

After the window is established, the message loop will be entered. During this time, WindowPro is called to handle each message.

When the window is established, the message processing function is set, typically AFXWndProc, which will call AFXCallWndProc, and AFXCallWndProc will eventually call to virtual functions WindowProc. Features:

Allow derived classes to add processing before message processing.

CWND implementation:

Lresult CWnd :: WindowProc (Uint Message, WParam WPARAM, LPARAM LPARAM)

{

LRESULT LRESULT = 0;

File: // Mainly by ONDMSG to complete the category, decomposition processing.

IF (! OnWndmsg (Message, WPARAM, LPARAM, & LRESULT))

File: // The remainder is handled by the default command.

LResult = DefWindowProc (Message, WPARAM, LPARAM);

Return LRESULT;

}

Attached: OnWndMSG process

In OnWndMSG, according to the nature of the message, classified into command messages, notification messages, ordinary news

Handled by ONCOMMAND, ONNOTIFY ...

Bool CWnd :: OnWndmsg (Uint Message, WPARAM WPARAM, LPARAM LPARAM, LRESULT * PRESULT)

{

// If it is a WM_COMMAND message, processed by the virtual function oncommand,

// WM_COMMAND is issued by the menu, toolbar, etc., indicating a specific command, and the window message is different.

IF (Message == WM_COMMAND)

{

....

Oncommand (WPARAM, LPARAM))

....

}

// If the message is WM_NOTIFY, that is, the notification message, by the virtual function ONNOTIFY,

IF (Message == WM_NOTIFY)

{

.....

ONNOTIFY (WPARAM, LPARAM, & LRESULT))

.....

}

// Processing for special messages:

WM_ACTIVATE ...

WM_SETCURSOR ...

// ordinary news

.......

// Find the message processing function corresponding to the message in the class message map.

// Parameter conversion, etc. ...

.......

// After finding it, call this function.

MMF.PFN = LPENTRY-> PFN;

LRESULT = (this -> * mmf.pfn_lwl) (WPARAM, LPARAM);

.......

}

6. Oncommand

Call the timing:

In OnWndMSG, if the message is WM_COMMAND, that is, the command message, the oncommand will be called;

The command processing can be operated in OnCommand.

CWnd implementation: file: // See the analysis of the command update mechanism

Bool CWnd :: OnCommand (WParam WPARAM, LPARAM LPARAM)

{

.....

// Trial call oncmdmsg (, cn_update_command_ui ..) See if the current command item is valid

CTESTCMDUI STATE;

State.m_nid = NID;

Oncmdmsg (NID, CN_UPDATE_COMMAND_UI, & State, Null;

If the if (...) // command is valid when the flag is commanded: CN_COMMAND

Ncode = CN_COMMAND;

....

/ / If it is a notification message of the sub-window, reflects to the sub-window ????, if the subsequent window has the appropriate processing, then return. If it is not processed, or it is handled as a command.

// There is a part of the notification message to send by WM_Command

IF (REFLECTLASTMSG (HWNDCTRL))

Return true; // Eaten by child

/ / The command message is finished, call the virtual function oncmdmsg !!!!!!

Return Oncmdmsg (NID, NCODE, NULL, NULL);

}

For the specific process of command processing, see Articles related articles.

7. Ononnotify

BOOL CWND :: ONNOTIFY (WPARAM, LPARAM LPARAM, LRESULT * PRESULT)

Call the timing:

In WM_NOTIFY, ONDMSG is handled for the notification message to handle the notification message if the message is WM_NOTIFY.

The virtual function onnotify provides an interface to manage the notification message in the derived class.

CWnd Realization: BOOL CWND :: Onnotify (WPARAM, LPARAM LPARAM, LRESULT * PRESULT) {..... File: // Reflect the notification message to the window issued, by it, if the window is not processed, ONCMDMSG processing. IF (REFLECTLASTMSG (HWNDCTRL, PRESULT)) Return True; // Eaten By Child ..... file: // is handled by ONCMDMSG. Corresponding message mapping macro is Return oncmdmsg (NID, Makelong (Ncode, WM_Notify), & Notify, NULL);

About the message reflection:

Controls typically inform the parent window in the form of a notification message. Processing by the parent window.

The reflective mechanism of the MFC can transmit the notification message back to the original window, and the processing of the event is obtained in the message mapping system of the original window. This makes it easy to package the window.

If the sub-window does not have a reflection function of the notification, the notification message is processed by the parent window.

In ReflectlastMSG, PWND-> SendChildNotifylastmsg will be called (PWND is a pointer to the sub-window)

The virtual function onChildNotify will be called in SendChildNotifyLastMSG.

In the onChildNotify in the sub-window, you can add a reflected message to the process before processing.

8. OnChildNotify

Bool CWnd :: OnChildNotify (Uint UMSG, WPARAM WPARAM, LPARAM LPARAM, LRESULT * PRESULT)

Call the timing:

When the window is notified to the parent window, the onChildNotify will be called first when it is reflected.

You can monitor the notification message from the parent window in this function.

CWND implementation:

Call CWND member ReflectChildNotify

The processing of the notification message is actually done by the original message, the command processing process is completed. Different, their message, the command value is adjusted to distinguish the message, command.

In the message mapping item of the class, the reflected message processing macro completes the association of the corresponding notification message and the processing function.

Bool CWnd :: ReflectchildNotify (uint UMSG, WPARAM WPARAM, LPARAM LPARAM, LRESULT * PRESULT)

{

// Processes the returned message classification to a specific message format

Switch (UMSG)

{

// ordinary news

// WM_HSCROLL, WM_VSCROLL: .........

.....

/ / Convert into a reflected message number and process the function by the command. (In the message mapping, the serial number of the reflected message is WM_REFLECT_BASE UMSG)

Return CWnd :: OnWndmsg (WM_REFLECT_BASE UMSG, WPARAM, LPARAM, PRESULT);

// If it is WM_COMMAND

Case WM_COMMAND:

{

.....

/ / Directly give the window's oncmdmsg, and the serial number of the command is changed accordingly to distinguish between the same command received by the window, and there are different message mapping items. CWnd :: ONCMDMSG (0, Makelong (Ncode, WM_REFLECT_BASE WM_COMMAND), NULL, NULL)

.....

}

// If it is a WM_NOTIFY notification

Case WM_NOTIFY:

{

// .......

// Treatment of OnCMDMSG. Change the command number.

CWnd :: ONCMDMSG (0, Makelong (Ncode, WM_REFLECT_BASE WM_NOTIFY),? IFY, NULL

.....

}

// Color class

IF (UMSG> = WM_CTLCOLORMSGBOX && UMSG <= WM_CTLCOLORSTATIC)

{

....

CWnd :: OnWndmsg (WM_REFLECT_BASE WM_CTLCOLOR, 0, (LPARAM) & CTL, PRESULT);

....

}

......

}

9. DefWindowProc

Call the timing:

After WindowProc, the message is not found in WINDMSG, will be handled by DEFWINDOWPROC.

In DEFWINDOWPROC, you can add appropriate operations for these unprocessed messages.

CWnd implementation

Lresult CWnd :: DefWindowProc (Uint NMSG, WPARAM WPARAM, LPARAM LPARAM)

{

IF (M_PFNSUPER! = NULL)

Return :: CallWindowProc (M_PFNSUPER, M_HWND, NMSG, WPARAM, LPARAM);

WndProc PfnWndProc;

IF (pfnwndproc = * getsuperWndProcaddr ()) == null)

Return :: DefWindowProc (M_HWND, NMSG, WPARAM, LPARAM);

Else

Return :: CallWindowProc (PfnWndProc, M_HWND, NMSG, WPARAM, LPARAM);

}

10. DESTROYWINDOW

Let's see the implementation of CWnd on the DESTROYWINDOW.

Bool cwnd :: destroyWindow ()

{

....

// Destroy the window

IF (m_pctrlsite == NULL)

BRESULT = :: DestroyWindow;

Else

BRESULT = m_pctrlsite-> destroyControl ();

....

// C window object and window detachment

Detach ();

}

In this implementation, the API: Bool DestroyWindow (HWND HWND) is called;

The DESTROYWINDOW of the API will send WM_DESTROY and WM_NCDESTROY messages to the window.

Call the timing:

1. For the main window: (cframeWnd)

DESTROYWINDOW will be called when the window receives a closed message.

Turn off the message:

Select an exit on the menu, will give an ID_APP_EXIT command, this command has a default implementation in CWINAPP: ONAPPEXIT: Send WM_Close to the main window;

In addition, press the window clock button to give the window a WM_CLOSE message.

Processing on the default processing on WM_CLOSE Onclose ()

Void cframewnd :: onClose ()

{

....

DESTROYWINDOW ();

....

}

2. For other windows

When the main window is destroyed :: DESTROYWINDOW, this API will send WM_DESTROY and WM_NCDESTROY messages to the window. And automatically complete the destruction of the completion sub-window.

In the MFC, the DESTROYWINDOW virtual function of the sub-window is not called, but it can be called when it is needed. The destruction of the control sub-window.

11. PostncDestroy

Call the timing:

After the window is destroyed, the process function on WM_NCDESTROY is called.

The deletion of the C window object will generally complete the deletion of C window objects in PostNCDESTROY.

CWND implementation:

air

CframeWnd implementation

Delete this; (delete window object)

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

New Post(0)