Going out of MFC subclass of maze
Key Words: Subclass SubclassWindow MFC Message Mechanism
Many Windows programmers are skipping SDK directly using RAD development tools [or VC, I think VC should not belong to rad], some people may be more unfamiliar with the child.
Let's take a look at what is the subclass of Windows. Windows gives us or tells itself to a lot of rich general controls, such as: Edit, ComboBox, ListBox ..., etc., these controls are rich in function, which can bring us great aspects for our development work. Imagine: We are single How hard is to achieve an edit control! However, in actual development, these standard controls are still in power, such as: In our application, I ask for an edit to get the teacher's evaluation of the students A, B, C [Don't tell me, you want to use ComboBox implementation J], this When it is required to prohibit the input operation of other letters, numbers in Edit, what should I do? The EDIT control itself does not provide this mechanism, we can use a good solution to such issues well.
We know that every Windows window [here is EDIT] has a window handling function to be responsible for the message processing, subcatenification is to use our own message processing function to replace the original, standard handler of the window. Of course, our own window handling function is only concerned about those specific messages [of course is WM_CHAR], while other messages are sent to the original window function processing. The implementation method in the SDK is to call the function setWindowlong:
WndProc * OldWndProc = (WndProc) setWindowlong (HWND, GWL_WNDPROC, (DWORD) AFXGetAfxWndProc ());
Among them, AfxGetAfxWndProc () is our own window handling function, which may handle other messages by returning the original window to handle the function pointer OldWndProc by the return of the original window, which may be handled by the standard method. Please refer to the relevant information.
But in the MFC "Age", everything is packaged, the original window is registered, the window function is not seen [or "I want to stealth], I want to be interested in the" planing root ascending "programmer is interested in MFC. Subcolarization mechanism, I have made a summary of "exploration" you have made, I hope to give you some points.
We first use the MFC to implement the requirements mentioned above: A Edit control that can only be entered by A, B, and C.
The interface is started as follows:
You can only enter A, B, C when entering, and only one letter is allowed.
Implementation:
First, a self-owned class CSUPEREDIT, Ctrl W processes WM_CHAR, and then edit this message processing function:
Void Csupers :: onchar (uint nchar, uint nrepcnt, uint nflags)
{
// Todo: add your message handler code here and / or call default
TCHAR CH [20];
GetWindowText (CH, 20);
IF (Strlen (CH) == 1 && (nchar <= 'c' && nchar> = 'a'))))
Return;
IF (nchar! = 'a'
&& nchar! = 'b'
&& nchar! = 'c'
)
Return;
Cedit :: onchar (nchar, nrepcnt, nflags);}
Then add a data member CSUPEREDIT M_EDIT to our CPROG1DLG class, add: on cprog1dlg :: OnIndialog:
M_EDit.subclassdlgitem (idc_edit1, this);
m_EDit.setwindowText ("
And handle the notification message sent to Dialog: en_setfocus:
Void cprog1dlg :: Onsetfocusedit1 ()
{
// Todo: Add Your Control Notification Handler Code Here
m_edit.setwindowText ("");
m_edit.setfocus ();
}
OK, everything is done! What is easy to compare with SDK's subclass of SDK!
Let's take a look at what MFC has done in the end! Here mainly solves the two problems that make the initiator to relatively confused:
1, m_edit just a C class object we define, why can it call its member function setWindowText to control the resources number: IDC_EDIT1 control?
2, why can the CSUPEREDIT class handle WM_CHAR messages?
Everyone knows that controlling Windows windows, controls, resources ... are all achieved by their handle, such as HHANDLE, HWND, HDC is handle, which is a 32-bit long plastic data, stored in a specific area in Windows, We can understand it in order to point to the window, control, resource index we want, with it, we can control the object we want to control.
Here you can think of why most API functions have a parameter hWnd hwnd!
Bool setWindowText
HWND HWND, // Handle to Window or Control
LPCTSTR LPSTRING / / TITLE OR TEXT
);
Our C variable m_edit wants to control IDC_EDIT1, but also through its handle, but how is this achieved? You may notice m_edit.subclassdlgitem (idc_edit1, this); a sentence, right, this is the key!
After f9 here, after F5, the program arrives here, F11 keeps the subsclassdlgitem function:
BOOL CWND :: Subclassdlgitem (uint nid, cwnd * pparent)
{
Assert (pParent! = Null);
Assert (:: iswindow (pParent-> m_hwnd);
// Check for Normal Dialog Control First
HWND HWNDCONTROL = :: getdlgitem (pParent-> m_hwnd, nid);
IF (hWndControl! = null)
Return SubclassWindow (HWNDControl);
#ifndef _AFX_NO_OCC_SUPPORT
IF (pParent-> m_pctrlcont! = null)
{
// Normal Dialog Control NOT FOUND
Colecontrolsite * psite = pparent-> m_pctrlcont-> FindItem (NID); if (psite! = Null)
{
Assert (psite-> m_hwnd! = Null);
Verify (SubclassWindow);
#ifndef _AFX_NO_OCC_SUPPORT
// if the control has reparented itself (E.G., Invisible Control),
// Make Sure That The CWnd Gets Properly Wired To ITS Control Site.
IF (pParent-> m_hwnd! = :: getParent (psite-> m_hwnd))
AttachControlsite (PParent);
#ENDIF / /! _ AFX_NO_OCC_SUPPORT
Return True;
}
}
#ENDIF
Return False; // Control NOT FOUND
}
At the beginning of the code, you will check the incoming parent window, then
HWND HWNDCONTROL = :: getdlgitem (pParent-> m_hwnd, nid);
IF (hWndControl! = null)
Return SubclassWindow (HWNDControl);
This is a key code, first get the handle of our IDC_EDIT1 control with HWNDControl, then call
SubclassWindow function, this function is the key to the implementation, let's take a look at what it did:
BOOL CWND :: SubclassWindow (HWND HWND)
{
IF (! attach (hwnd))
Return False;
// allow any other subsclassing to occur
PRESUBCLASSWINDOW ();
// Now hook ion t AFX WNDPROC
WndProc * lplpfn = getsuperWndProcAddr ();
WndProc OldWndProc = (WndProc) :: SetWindowlong (HWND, GWL_WNDPROC, (DWORD) AFXGetAfxWndProc ());
ASSERT (OldWndProc! = (WndProc) AFXGetAfxWndProc ());
IF (* LPLPFN == NULL)
* LPLPFN = OldWndProc; // the first control of what type created
#ifdef _Debug
Else if (* LPLPFN! = OldWndProc)
{
Trace0 ("Error: Trying to Use SubclassWindow with incorrect cwnd / n");
Trace0 ("/ Tderived Class./N");
Trace3 ("/ ThWND = $% 04X (NIDC = $% 04x) IS Not a% HS. / N", (UINT) HWND,
_Afxgetdlgctrlid (hwnd), getRuntimeClass () -> m_lpszclassname);
Assert (false);
// undo the subclassingiffiffArSsert
:: Setwindowlong (HWND, GWL_WNDPROC, (DWORD) OldWndProc);
}
#ndifreturn true;
}
The function attach is as follows:
BOOL CWND :: Attach (HWND HWNDNEW)
{
Assert (m_hwnd == null); // only attach overce, Detach on Destroy
ASSERT (HWNDLEPERMANENT (HWNDNEW) == NULL);
// Must Not Already Be in Permanent Map
IF (hwndnew == null)
Return False;
ChandleMap * pmap = AFXMAPHWND (TRUE); // Create Map if not exist
Assert (pmap! = Null);
PMAP-> setPermanent (m_hwnd = hwndnew, this);
#ifndef _AFX_NO_OCC_SUPPORT
AttachControlsite (PMAP);
#ENDIF
Return True;
}
Here, it will be described here that PMAP-> setPermanent (m_hwnd = hwndnew, this); a sentence, it assigns our IDC_EDIT1 handle to class CSUPEREDIT's data member m_hwnd [Don't forget our CSUPEREDIT class is derived from CEDIT], everyone may I have clearly understood something, nice, in m_edit.setwindowtext ("
Void CWnd :: setWindowText (LPCTSTR LPSZSTRING)
{
Assert (: iswindow (m_hwnd));
IF (m_pctrlsite == NULL)
:: SetwindowText (m_hwnd, lpszstring);
Else
m_pctrlsite-> setWindowText (lpszstring);
}
The functions of other CEDIT classes are also packaged around the "M_HWND API function".
And the DDX_Control method we use is also called SubclassWindow.
how about it? The first question is the dragon to understand?
Take a look at the second question: Why can the CSUPEREDIT class handle WM_CHAR messages?
There may be some friends now doubt, although M_EDit is implemented by the handle, but the message sent to the EDIT's standard processing function is saved, how is the WM_CHAR?
If the message is like running to the EDIT's standard handler, then, it is of course not handling! I don't know if you have seen such a small paragraph in the SubclassWindow function above.
// Now hook ion t AFX WNDPROC
WndProc * lplpfn = getsuperWndProcAddr ();
WndProc OldWndProc = (WndProc) :: SetWindowlong (HWND, GWL_WNDPROC, (DWORD) AFXGetAfxWndProc ());
ASSERT (OldWndProc! = (WndProc) AFXGetAfxWndProc ());
IF (* LPLPFN == NULL)
* LPLPFN = OldWndProc; // the first control of what type created
Then talk to the SDK neutrical mechanism that we started, understand it? The MFC is here for the ghosts who don't know the ghosts! This AFXGetAfxWndProc () function is like this:
WndProc AFXAPI AFXGETAFXWNDPROC ()
{
#ifdef _AFXDLL
Return AFXGETMODULESTATE () -> M_PFNAFXWNDPROC;
#ELSE
Return & AfxWndProc;
#ENDIF
}
I didn't know if I didn't know if I didn't know if I didn't know if I didn't know if I still remember that the MFC's command routing mechanism was starting with this function!
Thus when the program receives WM_CHAR sent to EDIT, this should call the Edit standard window processing function. Now it is changed to call LResult Callback AfxWndProc (HWND HWND, UINT NMSG, WPARAM WPARAM, LPARAM LPARAM), then the WM_CHAR message is a series The rogue, eventually successfully reached our handler Csupers :: onchar (uint nchar (uint nrepcnt, uint nflags) Please read from page 566].
Finally, we walked out of the FMC subclass of maze.
9CBS roast chicken wings
2002-12-3
[Finish]
PS: This person is scattered, if there is any place to "laugh", be sure to inform me.