Problem getting to Event Procedure for a SubClassed Control
-
I have made a smart edit control class called CStringEdit that is subclassed off the CEdit class. This control works very nicely for me when I include it as a member variable control in a Dialog class. The purpose of this control is to let me have a lot more run time control over a users data entry in a dialog edit box. The CStringEdit class has interfaces to perform these functions: void SetFixedLen(BOOL bFixedLen) ... used to set the string to fixed length padded if necessary to the right at the call to GetText(). Defaults to FALSE. void SetMaxLength(int nMax) ... used to set the maximum string length. The default value of zero means no length restriction and FixedWidth feature is ignored. void SetLegal(LPCSTR lpszLegal) ... used to enter a string of characters that are legal in the edit box. Defaults to NULL string which means that all characters are legal. void SetIllegal(LPCSTR lpszIllegal) ... used to put in a string of characters that are specifically illegal in the editbox. Defaults a NULL string such that there are no illegal characters. void SetText(LPCSTR lpszText) ... used to send intial text to the edit box. void GetText(CString& strText) ... used to get back out the edited text string. This control class uses a connection that I setup with the ClassWizard on the OnUpdate() message to validate the edit box contents at each instance that the control thinks there has been a change to the text content and it thinks it is time to re-display the control contents. In this event routine I do the validation to limit the string length and verify if the string contents are valid. It works just dandy!!! :) NOW FOR MY PROBLEM....... I have a particular instance of this control in a dialog where there needs to be some additional real time validation of the edit box content that is dependent upon other things on that same dialog. I have tried to connect the specific instance of this edit control member variable to its own OnUpdate() procedure in the dialog class. Once again this cinnection was mapped using the Class Wizard. My problem is that the event procedure is never being invoked. :confused: Can anyone help me figure out why this does not work?? I can send the whole class source code plugged into a simple demo app if my write-up here is not complete enough.... Thanks from a new VC++ 6 user. Mike
-
I have made a smart edit control class called CStringEdit that is subclassed off the CEdit class. This control works very nicely for me when I include it as a member variable control in a Dialog class. The purpose of this control is to let me have a lot more run time control over a users data entry in a dialog edit box. The CStringEdit class has interfaces to perform these functions: void SetFixedLen(BOOL bFixedLen) ... used to set the string to fixed length padded if necessary to the right at the call to GetText(). Defaults to FALSE. void SetMaxLength(int nMax) ... used to set the maximum string length. The default value of zero means no length restriction and FixedWidth feature is ignored. void SetLegal(LPCSTR lpszLegal) ... used to enter a string of characters that are legal in the edit box. Defaults to NULL string which means that all characters are legal. void SetIllegal(LPCSTR lpszIllegal) ... used to put in a string of characters that are specifically illegal in the editbox. Defaults a NULL string such that there are no illegal characters. void SetText(LPCSTR lpszText) ... used to send intial text to the edit box. void GetText(CString& strText) ... used to get back out the edited text string. This control class uses a connection that I setup with the ClassWizard on the OnUpdate() message to validate the edit box contents at each instance that the control thinks there has been a change to the text content and it thinks it is time to re-display the control contents. In this event routine I do the validation to limit the string length and verify if the string contents are valid. It works just dandy!!! :) NOW FOR MY PROBLEM....... I have a particular instance of this control in a dialog where there needs to be some additional real time validation of the edit box content that is dependent upon other things on that same dialog. I have tried to connect the specific instance of this edit control member variable to its own OnUpdate() procedure in the dialog class. Once again this cinnection was mapped using the Class Wizard. My problem is that the event procedure is never being invoked. :confused: Can anyone help me figure out why this does not work?? I can send the whole class source code plugged into a simple demo app if my write-up here is not complete enough.... Thanks from a new VC++ 6 user. Mike
I sort of lost you in the last paragraph where you have defined your problem. Are you trying to call a message handler function through direct function call ? If this being the problem then rather than calling the function directly - you must use PostMessage() (see MSDN help on PostMessage() ) to invoke the event handler. PostMessage() a parameter that contains the MESSAGE_ID, LPARAM, and WPARAM If i incorrectly understood the problem then can you please elaborate it further -cheers -kashif manzoor peace to all
-
I have made a smart edit control class called CStringEdit that is subclassed off the CEdit class. This control works very nicely for me when I include it as a member variable control in a Dialog class. The purpose of this control is to let me have a lot more run time control over a users data entry in a dialog edit box. The CStringEdit class has interfaces to perform these functions: void SetFixedLen(BOOL bFixedLen) ... used to set the string to fixed length padded if necessary to the right at the call to GetText(). Defaults to FALSE. void SetMaxLength(int nMax) ... used to set the maximum string length. The default value of zero means no length restriction and FixedWidth feature is ignored. void SetLegal(LPCSTR lpszLegal) ... used to enter a string of characters that are legal in the edit box. Defaults to NULL string which means that all characters are legal. void SetIllegal(LPCSTR lpszIllegal) ... used to put in a string of characters that are specifically illegal in the editbox. Defaults a NULL string such that there are no illegal characters. void SetText(LPCSTR lpszText) ... used to send intial text to the edit box. void GetText(CString& strText) ... used to get back out the edited text string. This control class uses a connection that I setup with the ClassWizard on the OnUpdate() message to validate the edit box contents at each instance that the control thinks there has been a change to the text content and it thinks it is time to re-display the control contents. In this event routine I do the validation to limit the string length and verify if the string contents are valid. It works just dandy!!! :) NOW FOR MY PROBLEM....... I have a particular instance of this control in a dialog where there needs to be some additional real time validation of the edit box content that is dependent upon other things on that same dialog. I have tried to connect the specific instance of this edit control member variable to its own OnUpdate() procedure in the dialog class. Once again this cinnection was mapped using the Class Wizard. My problem is that the event procedure is never being invoked. :confused: Can anyone help me figure out why this does not work?? I can send the whole class source code plugged into a simple demo app if my write-up here is not complete enough.... Thanks from a new VC++ 6 user. Mike
Your problem is that you have two
OnUpdate
s, one inCStringEdit
and one in the parent dialog, and the latter handler is not being called, right? If so, then the solution goes as follows:-
In
StringEdit.h
, changeafx_msg void OnUpdate();
to
afx_msg BOOL OnUpdate();
Do the necessary modifications on the
.cpp
as well, and have this handler returnFALSE
. -
In
StringEdit.cpp
, replaceON_CONTROL_REFLECT(EN_UPDATE, OnUpdate)
with
ON_CONTROL_REFLECT_EX(EN_UPDATE, OnUpdate)
That should do it. The changes indicate the framework that the reflection handler of
CStringEdit
allows further processing by the parent (by returningFALSE
instead ofTRUE
as the code forON_CONTROL_REFLECT
does internally). Joaquín M López Muñoz Telefónica, Investigación y Desarrollo -
-
Your problem is that you have two
OnUpdate
s, one inCStringEdit
and one in the parent dialog, and the latter handler is not being called, right? If so, then the solution goes as follows:-
In
StringEdit.h
, changeafx_msg void OnUpdate();
to
afx_msg BOOL OnUpdate();
Do the necessary modifications on the
.cpp
as well, and have this handler returnFALSE
. -
In
StringEdit.cpp
, replaceON_CONTROL_REFLECT(EN_UPDATE, OnUpdate)
with
ON_CONTROL_REFLECT_EX(EN_UPDATE, OnUpdate)
That should do it. The changes indicate the framework that the reflection handler of
CStringEdit
allows further processing by the parent (by returningFALSE
instead ofTRUE
as the code forON_CONTROL_REFLECT
does internally). Joaquín M López Muñoz Telefónica, Investigación y DesarrolloI made the changes you suggested, (you were right on track of understanding what was not working for me). Now when I compile the program and try to run it there always is a run time error that happens. I get a box that pops up a with "Unhandled Exception". Hitting OK to this dumps me into the debugger with the current code pointer positioned at the BEGIN_MESSAGE_MAP(CStringEdit, CEdit) line of the CStringEdit class code. I have no idea of what casues this or what to do about it. Take a look at what I now have and tell me if you can see anything wrong with it. Here is what I have: In the customized edit control called CStringEdit header file StringEdit.h there is: class CStringEdit : public CEdit { .... .... protected: // Generated message map functions //{{AFX_MSG(CStringEdit) afx_msg BOOL OnUpdate(); //}}AFX_MSG DECLARE_MESSAGE_MAP() ... ... } Then in the implementation, StringEdit.cpp, file I have the following code following your suggestion. ////////////////////////////////////////////////// // // BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros // BEGIN_MESSAGE_MAP(CStringEdit, CEdit) //{{AFX_MSG_MAP(CStringEdit) ON_CONTROL_REFLECT_EX(EN_UPDATE, OnUpdate) //}}AFX_MSG_MAP END_MESSAGE_MAP() And for the actual update routine itself in the same file there is the member function as shown below. This function is supposed to validate the edit box content per the definitions of my CStringEdit class but the parent dialog may want to further validate the edit box content. BOOL CStringEdit::OnUpdate() { // local code in here to validate edit contents and possibly // modify and or reject the most recent changes by replacing // edit content with last know valid content. ... ... return(FALSE); } Now in the parent dialog class the code that I have now in place to attempt to provide the further validation of the looks as follows. In the dialog header file there is this code... class CEditCounters : public CDialog { ... ... // Dialog Data //{{AFX_DATA(CEditCounters) enum { IDD = IDD_EDIT_COUNTERS }; ... CStringEdit m_CntFormat_Edit; ... //}}AFX_DATA ... // Generated message map functions //{{AFX_MSG(CEditCounters) ... afx_msg void OnUpdateCntFormatEdit(); ... //}}AFX_MSG DECLARE_MESSAGE_MAP() private: ... ... // function to check a counter format string BOOL CEditCounters::FormatCheck(CString *pCntFormat); }; And for completeness (please bear wi
-
-
I made the changes you suggested, (you were right on track of understanding what was not working for me). Now when I compile the program and try to run it there always is a run time error that happens. I get a box that pops up a with "Unhandled Exception". Hitting OK to this dumps me into the debugger with the current code pointer positioned at the BEGIN_MESSAGE_MAP(CStringEdit, CEdit) line of the CStringEdit class code. I have no idea of what casues this or what to do about it. Take a look at what I now have and tell me if you can see anything wrong with it. Here is what I have: In the customized edit control called CStringEdit header file StringEdit.h there is: class CStringEdit : public CEdit { .... .... protected: // Generated message map functions //{{AFX_MSG(CStringEdit) afx_msg BOOL OnUpdate(); //}}AFX_MSG DECLARE_MESSAGE_MAP() ... ... } Then in the implementation, StringEdit.cpp, file I have the following code following your suggestion. ////////////////////////////////////////////////// // // BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros // BEGIN_MESSAGE_MAP(CStringEdit, CEdit) //{{AFX_MSG_MAP(CStringEdit) ON_CONTROL_REFLECT_EX(EN_UPDATE, OnUpdate) //}}AFX_MSG_MAP END_MESSAGE_MAP() And for the actual update routine itself in the same file there is the member function as shown below. This function is supposed to validate the edit box content per the definitions of my CStringEdit class but the parent dialog may want to further validate the edit box content. BOOL CStringEdit::OnUpdate() { // local code in here to validate edit contents and possibly // modify and or reject the most recent changes by replacing // edit content with last know valid content. ... ... return(FALSE); } Now in the parent dialog class the code that I have now in place to attempt to provide the further validation of the looks as follows. In the dialog header file there is this code... class CEditCounters : public CDialog { ... ... // Dialog Data //{{AFX_DATA(CEditCounters) enum { IDD = IDD_EDIT_COUNTERS }; ... CStringEdit m_CntFormat_Edit; ... //}}AFX_DATA ... // Generated message map functions //{{AFX_MSG(CEditCounters) ... afx_msg void OnUpdateCntFormatEdit(); ... //}}AFX_MSG DECLARE_MESSAGE_MAP() private: ... ... // function to check a counter format string BOOL CEditCounters::FormatCheck(CString *pCntFormat); }; And for completeness (please bear wi
Seems to me everything's fine. Have you tried with "Rebuild All"? Sometimes it helps. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
-
Seems to me everything's fine. Have you tried with "Rebuild All"? Sometimes it helps. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo
Thanks for looking at all my code!! I tried the ReBuild All again (I had done this before anyway out of normal practice) but it does not help the problem. I have now done some debug investigation. I set two breakpoints. One at the UpDate function in the CStringEdit class and one at the Update handler code in the parent dialog code. What seems to be happening is that the two breakpoints are being hit alternately first the edit control update and then the parent update routine in a never ending loop. I see the ESP register steadily going downard in addresses at each breakpoint. I am guessing that there is an interlock in here that some how that makes the stack grow till it reaches its lower bound and tries to reference memory outside my programs stack area. DOes this seem like this could happen?? And if so how does one fixup to prevent a deadly loop like this from happening?
-
Thanks for looking at all my code!! I tried the ReBuild All again (I had done this before anyway out of normal practice) but it does not help the problem. I have now done some debug investigation. I set two breakpoints. One at the UpDate function in the CStringEdit class and one at the Update handler code in the parent dialog code. What seems to be happening is that the two breakpoints are being hit alternately first the edit control update and then the parent update routine in a never ending loop. I see the ESP register steadily going downard in addresses at each breakpoint. I am guessing that there is an interlock in here that some how that makes the stack grow till it reaches its lower bound and tries to reference memory outside my programs stack area. DOes this seem like this could happen?? And if so how does one fixup to prevent a deadly loop like this from happening?
Actually I found that my check code in the dialog was never happy with the edit text and was changing the edit box content...This apparently cases the edit control to get another update message and so the process went on till some 12 megabytes of stack get used up!!!! Thanks again,,,I think I am on track now of how to correct the problem. Your help with ON_CONTROL_REFLECT_EX is more than appreciated !! Mike Karas
-
Actually I found that my check code in the dialog was never happy with the edit text and was changing the edit box content...This apparently cases the edit control to get another update message and so the process went on till some 12 megabytes of stack get used up!!!! Thanks again,,,I think I am on track now of how to correct the problem. Your help with ON_CONTROL_REFLECT_EX is more than appreciated !! Mike Karas
In case it is of any help, I suggest you follow the following policy when implement
OnUpdate
: Have a boolean flag, saym_bInOnUpdate
to prevent reentrancy, and do not callSetWindowText
till you've parsed the whole string. Sort of like this:BOOL CStringEdit::OnUpdate()
{
if(m_bInOnUpDate)return TRUE;
m_bInOnUpDate=TRUE;CString str;
GetWindowText(str);// reject invalid characters from str
SetWindowText(str);
m_bInOnUpDate=FALSE;
}(Actually, either of these two techniques would suffice alone.) As a quality of implementation issue, you can also treat the selection (the highlithed portion) of the edit box and make it consistent with your "purged" string. Use
GetSel
/SetSel
for this. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo