Now, we can thoroughly analyze the cwnd class encapsulation mechanism.
In terms of window handle ing, cwnd uses an undisclosed kind of chandlemap for management. When you create a window using cwnd and a derived class, a handle ing is created and the ing is deleted when the window is destroyed. A chandlemap object created in MFC manages the ing between all cwnd instances and window handles. This object is created and obtained through an internal global function afxmaphwnd.
6.3.1 use operation ing Functions
Chandlemap mainly includes three member functions: setpermanent () (ing), removehandle () (ing deletion), and lookuppermanent () (find the object pointer corresponding to the specified handle in the ing ). The following code is the three cwnd member functions mapped to the operation handle:
// Find the corresponding cwnd object pointer in the ing Based on the specified window handle
Cwnd * Pascal cwnd: fromhandlepermanent (hwnd)
{// Get the ing management object
Chandlemap * pmap = afxmaphwnd ();
Cwnd * pwnd = NULL;
If (pmap! = NULL)
{// Search for window objects in ing
PWnd = (CWnd *) pMap-> LookupPermanent (hWnd );
ASSERT (pWnd = NULL | pWnd-> m_hWnd = hWnd );
}
Return pWnd;
}
/* Based on the specified window handle, first find the corresponding CWnd object pointer in the ing. If the ing fails, a temporary CWnd object is created and associated with the handle, then return the object pointer. If the temporary object is not locked, it is automatically deleted when it is idle. */
CWnd * PASCAL CWnd: FromHandle (HWND hWnd)
{
// The parameter is TRUE. If the ing object is not created, it is automatically created.
CHandleMap * pMap = afxMapHWND (TRUE );
ASSERT (pMap! = NULL );
// Search for permanent ing first. If the ing fails, a temporary object is returned.
Cwnd * pwnd = (cwnd *) pmap-> fromhandle (hwnd );
# Ifndef _ afx_no_occ_support
Pwnd-> attachcontrolsite (pmap );
# Endif
Assert (pwnd = NULL | pwnd-> m_hwnd = hwnd );
Return pwnd;
}
// Create a cwing between the current cwnd object and the specified handle
Bool cwnd: attach (hwnd hwndnew)
{
// If a ing is established, ensure that the two maps one by one.
Assert (m_hwnd = NULL); // whether the object has been mapped
Assert (fromhandlepermanent (hwndnew) = NULL); // whether the handle has been mapped
If (hwndnew = NULL)
Return FALSE;
// The parameter is TRUE. If the ing object is not created, it is automatically created.
CHandleMap * pMap = afxMapHWND (TRUE );
ASSERT (pMap! = NULL );
// Create a ing
PMap-> SetPermanent (m_hWnd = hWndNew, this );
# Ifndef _ AFX_NO_OCC_SUPPORT
AttachControlSite (pMap );
# Endif
Return TRUE;
}
CWnd myWnd; myWnd. Attach (hWnd );
This creates a project, which is permanently associated.Mywnd AndHwnd. Call cwnd: fromhandle(Hwnd)
AMywndPointer. WhenMywnd
After deletion, the Destructor is automatically destroyed through the window function destroywindow.HWnd.If you don't want to do thisHwnd
Must be inMywnd Before the object is destroyedMyWnd
Phase separation. (Usually leaveMyWnd Defined Scope)
The member function Detach does this.
myWnd.Detach();
// Delete the existing handle ing of the current CWnd object
HWND CWnd: Detach ()
{
HWND hWnd = m_hWnd;
If (hWnd! = NULL)
{CHandleMap * pMap = afxMapHWND ();
If (pMap! = NULL)
// Delete the ing
PMap-> RemoveHandle (m_hWnd );
M_hWnd = NULL;
}
# Ifndef _ AFX_NO_OCC_SUPPORT
M_pCtrlSite = NULL;
# Endif
Return hWnd;
}
6.3.2 how does CWnd process window messages?
In terms of window message processing, CWnd uses window subclasses and message ing mechanisms. The knowledge about message ing is described in Chapter 9th, the following describes how CWnd applies subclass to process window messages. In fact, in the example in section 6.2, CBaseWnd has used a subclass method similar to CWnd to process window messages. The member function CBaseWnd: SubWindowClass () subclass The Window Process into CBaseWnd: MyBaseWndProc (). In this window, CBaseWnd: WindowProc () is called to process window messages. The original window process is stored in the member m_Super WndProc and called in the default processing.
At the beginning of Window Creation, CWnd uses the AfxWndProc () subclass window to call CWnd: WindowProc () to process window messages in AfxWndProc. The difference is that for specific message processing, CWnd: WindowProc () uses the message ing mechanism instead of calling fixed virtual functions. The original window procedure is stored in CWnd: m_pfnSuper and called in the default process CWnd: DefWindowProc.
Below are several CWnd member functions related to message processing:
// Used for the subclass Window Process
LRESULT CALLBACK
AfxWndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
// Special message which identifies the window as using AfxWndProc
If (nMsg = WM_QUERYAFXWNDPROC)
Return 1;
// All other messages route through message map
// Obtain the CWnd Object Pointer using a handle
CWnd * pWnd = CWnd: FromHandlePermanent (hWnd );
ASSERT (pWnd! = NULL );
ASSERT (pWnd-> m_hWnd = hWnd );
Return AfxCallWndProc (pWnd, hWnd, nMsg, wParam, lParam );
}
Lresult afxapi AfxCallWndProc (CWnd * pWnd, HWND hWnd, UINT nMsg,
WPARAM wParam = 0, LPARAM lParam = 0)
{......
// Call the CWnd virtual member function to process messages
LResult = pWnd-> WindowProc (nMsg, wParam, lParam );
......
Return lResult;
}
// Virtual functions that can be reloaded in the Class Wizard
LRESULT CWnd: WindowProc (UINT message, WPARAM wParam, LPARAM lParam)
{
// The OnWndMsg function processes message ing. If no processing function of the current message is found in the ing, false is returned.
LRESULT lResult = 0;
If (! OnWndMsg (message, wParam, lParam, & lResult ))
// If the current message is not mapped for processing, call the default processing function.
LResult = DefWindowProc (message, wParam, lParam );
Return lResult;
}
// Default message processing function, same as Default ()
LRESULT CWnd: DefWindowProc (UINT nMsg, WPARAM wParam, LPARAM lParam)
{
If (m_pfnSuper! = NULL)
// Call the original Window Process
Return: CallWindowProc (m_pfnSuper, m_hWnd, nMsg, wParam, lParam );
WNDPROC pfnWndProc;
If (pfnWndProc = * GetSuperWndProcAddr () = NULL)
// Call the default window processing process
Return: DefWindowProc (m_hWnd, nMsg, wParam, lParam );
Else
Return: CallWindowProc (pfnWndProc, m_hWnd, nMsg, wParam, lParam );
}
In addition to the preceding member functions, the cwnd class also defines two public members, subclasswindow () and unsubclasswindow (). The former is used to dynamically associate and subclass windows Windows using afxwndproc, the latter executes the opposite process. This means that a window created using Win32 API can be connected to the cwnd instance at any time by calling subclasswindow. Because the subclass operation is executed at the same time, it is like using the CREATE () function of cwnd to create this Windows window. The function code is as follows:
Bool cwnd: subclasswindow (hwnd)
{
// Hwnd should be a Windows window not associated with any cwnd instance
If (! Attach (hwnd) // create an association first, and then subclass
Return false;
// Call this virtual function before subclass to provide users with programming interfaces
Presubclasswindow ();
Wndproc * lplpfn = getsuperwndprocaddr ();/* get the original window function. If the current class has not been subclass window, return NULL */
// Use afxwndproc () to subclass the window
Wndproc oldwndproc = (wndproc): setwindowlong (hwnd, gwl_wndproc,
(DWORD) afxgetafxwndproc (); // obtain the window function of the afxwndproc () subclass.
Assert (oldwndproc! = (Wndproc) afxgetafxwndproc ());
If (* lplpfn = NULL)
* Lplpfn = oldwndproc; // Save the original window function, which is called by default during processing.
Return true;
}
Hwnd cwnd: unsubclasswindow ()
{
ASSERT (: IsWindow (m_hWnd ));
// Obtain the original Window Process
WNDPROC * lplpfn = GetSuperWndProcAddr ();
// Restore Window Process
SetWindowLong (m_hWnd, GWL_WNDPROC, (LONG) * lplpfn );
* Lplpfn = NULL;
// Separate the window object and window handle
Return Detach ();
}
Virtual void CWnd: PreSubclassWindow ()
{// This virtual function is called before subclass when a window is created, and also called in CWnd: SubclassWindow
// It does not perform any operations. You can reload it and subclass it as needed. In this way, The subclass process becomes the original window process and is called during the default message processing.
}
The encapsulation of window operations is well understood. The member CWnd: m_hWnd stores the ing window handle. Different window operation member functions generally encapsulate WIN32 APIs with the same name, use m_hWnd to call an API with the same name. The following lists several related member functions.
Void CWnd: SetWindowText (LPCTSTR lpszString)
{ASSERT (: IsWindow (m_hWnd);: SetWindowText (m_hWnd, lpszString );}
BOOL CWnd: IsIconic () const
{ASSERT (: IsWindow (m_hWnd); return: IsIconic (m_hWnd );}
Void CWnd: MoveWindow (int x, int y, int nWidth, int nHeight, BOOL bRepaint)
{ASSERT (: IsWindow (m_hWnd);: MoveWindow (m_hWnd, x, y, nWidth, nHeight, bRepaint );}
BOOL CWnd: SetWindowPos (const CWnd * pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)
{ASSERT (: IsWindow (m_hWnd ));
Return: SetWindowPos (m_hWnd, pWndInsertAfter-> GetSafeHwnd (), x, y, cx, cy, nFlags );}
CDC * CWnd: GetWindowDC ()
{Assert (: iswindow (m_hwnd); Return CDC: fromhandle (: getwindowdc (m_hwnd ));}
Int cwnd: releasedc (CDC * PDC)
{Assert (: iswindow (m_hwnd); Return: releasedc (m_hwnd, PDC-> m_hdc );}
Void cwnd: updatewindow ()
{Assert (: iswindow (m_hwnd);: updatewindow (m_hwnd );}
The subwindow management section of cwnd is described in Chapter 7th.