hansw77041
asked on
CFont error after closing program
My code opens a dialog and in the OnInitDialog() creates a font :
In the .h file
LOGFONT stFont;
CFont* m_pFont;
In the OnInitDialog()
m_pFont = new CFont;
memset( &stFont, 0, sizeof(LOGFONT));
stFont.lfHeight = 24;
stFont.lfCharSet = ANSI_CHARSET;
stFont.lfWeight = 400;
strcpy(stFont.lfFaceName,T EXT("Arial "));
stFont.lfPitchAndFamily = VARIABLE_PITCH;
VERIFY(m_pFont->CreateFont Indirect(& stFont));/ / create the font
When the dialog is no longer used:
In the PostNcDestroy()
if( m_pFont != NULL )
{
m_pFont->DeleteObject(); // breakpoint here confirms this is called.
}
In debug mode this error is reported on closing the program:
{143} client block at 0x003860B8, subtype 0, 8 bytes long.
Where 143 is the line m_pFont = new CFont;
I have stripped the code down to just the bare minimum and do not even use the font yet the error occurs.
I have also tried this:
if( m_pFont != NULL )
{
m_pFont->DeleteObject(); // breakpoint here confirms this is called.
delete m_pFont; // does not help
}
However in another dialog the Same Code does not generate any errors. !
With a bare minimum actually no functionality in the dialog I did not expect the error to occur.
Is there something special about destroying a CFont ?
Complied for Release there appears to be no error, I just do not like stuff like this and would liek to get rid of it if possible.
In the .h file
LOGFONT stFont;
CFont* m_pFont;
In the OnInitDialog()
m_pFont = new CFont;
memset( &stFont, 0, sizeof(LOGFONT));
stFont.lfHeight = 24;
stFont.lfCharSet = ANSI_CHARSET;
stFont.lfWeight = 400;
strcpy(stFont.lfFaceName,T
stFont.lfPitchAndFamily = VARIABLE_PITCH;
VERIFY(m_pFont->CreateFont
When the dialog is no longer used:
In the PostNcDestroy()
if( m_pFont != NULL )
{
m_pFont->DeleteObject(); // breakpoint here confirms this is called.
}
In debug mode this error is reported on closing the program:
{143} client block at 0x003860B8, subtype 0, 8 bytes long.
Where 143 is the line m_pFont = new CFont;
I have stripped the code down to just the bare minimum and do not even use the font yet the error occurs.
I have also tried this:
if( m_pFont != NULL )
{
m_pFont->DeleteObject(); // breakpoint here confirms this is called.
delete m_pFont; // does not help
}
However in another dialog the Same Code does not generate any errors. !
With a bare minimum actually no functionality in the dialog I did not expect the error to occur.
Is there something special about destroying a CFont ?
Complied for Release there appears to be no error, I just do not like stuff like this and would liek to get rid of it if possible.
ASKER
If the delete fails what can be done to make it work ?
In another dialog the same code funxtions without errors ! Why /how can delete fails ?
Thanks.
Hans W
In another dialog the same code funxtions without errors ! Why /how can delete fails ?
Thanks.
Hans W
I think the font object is still in use and therefore the error occurs. Do you have at first a code line "CDialog::OnNcDestroy()" in PostNcDestroy? May be, this will solve the problem.
Why do you use a pointer for the font object? You'll have much less trouble without a pointer.
Why do you use a pointer for the font object? You'll have much less trouble without a pointer.
ASKER
mb
Thanks I'll try that. However I've always deleted "stuff" before calling CDialog::OnNcDestroy() !
Using pointers for the font object: Habit and old code which has worked for years, in fact as I said it's working fine in the same program !
After taking the dialog class down to the bare minimum I really expected the problem to go away! Why it fails now and has worked for years is the mystery !
hansw
Thanks I'll try that. However I've always deleted "stuff" before calling CDialog::OnNcDestroy() !
Using pointers for the font object: Habit and old code which has worked for years, in fact as I said it's working fine in the same program !
After taking the dialog class down to the bare minimum I really expected the problem to go away! Why it fails now and has worked for years is the mystery !
hansw
Hi,
I think you are using SetFont to set that font to some window. The font can't be deleted if it is refereing to some window.
As per MSDN Article:
The SetFont() accepts a CFont object as a parameter; the control uses the specified font to display its text. The SetFont() function is implemented to send a WM_SETFONT message to the control with the font handle that corresponds to the CFont object.
An application can delete the font specified in a WM_SETFONT message only under certain circumstances; these same restrictions apply to the CFont object specified in a SetFont() call.
Specifically, do not destroy the specified CFont object until after the CWnd control has been destroyed. Windows does not copy the font specified in a SetFont() call. If the font is destroyed before the control is destroyed, unpredictable results can occur.
For example, when an application uses SetFont() to change the font a dialog box uses, the application should not destroy the CFont object until after it has destroyed the dialog box. Make the CFont object a member variable of the derived dialog box class instead of making the font a local variable in one of the functions in the class. This is the best method to ensure that the CFont object exists for the lifetime of the dialog box. When the application destroys the dialog box, the dialog box class destructor automatically calls the CFont destructor to delete the font handle.
The best time to specify the font for any controls in the dialog box is in the OnInitDialog() member function.
The code below demonstrates deriving a dialog box class from CModalDialog and using the SetFont() member function:
Sample Code
/*
* Compiler options needed: None
*/
class CMyAboutBox : public CDialog
{
CFont m_font;
public:
// Constructor -- This code assumes a dialog box
// template named "ABOUTDLG" in the application's .RC file.
CMyAboutBox(CWnd* pParentWnd = NULL) :
CModalDialog("ABOUTDLG", pParentWnd) {};
BOOL OnInitDialog();
};
// OnInitDialog() function -- Called after Windows creates
// the dialog box but before it is painted on the screen.
BOOL CMyAboutBox::OnInitDialog( )
{
LOGFONT lf; // Used to create the CFont.
CDialog::OnInitDialog(); // Call default ::OnInitDialog
memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
lf.lfHeight = 20; // Request a 20-pixel-high font
strcpy(lf.lfFaceName, "Arial"); // with face name "Arial".
m_font.CreateFontIndirect( &lf); // Create the font.
// Use the font to paint a control. This code assumes
// a control named IDC_TEXT1 in the dialog box.
GetDlgItem(IDC_TEXT1)->Set Font(&m_fo nt);
return TRUE;
}
I think you are using SetFont to set that font to some window. The font can't be deleted if it is refereing to some window.
As per MSDN Article:
The SetFont() accepts a CFont object as a parameter; the control uses the specified font to display its text. The SetFont() function is implemented to send a WM_SETFONT message to the control with the font handle that corresponds to the CFont object.
An application can delete the font specified in a WM_SETFONT message only under certain circumstances; these same restrictions apply to the CFont object specified in a SetFont() call.
Specifically, do not destroy the specified CFont object until after the CWnd control has been destroyed. Windows does not copy the font specified in a SetFont() call. If the font is destroyed before the control is destroyed, unpredictable results can occur.
For example, when an application uses SetFont() to change the font a dialog box uses, the application should not destroy the CFont object until after it has destroyed the dialog box. Make the CFont object a member variable of the derived dialog box class instead of making the font a local variable in one of the functions in the class. This is the best method to ensure that the CFont object exists for the lifetime of the dialog box. When the application destroys the dialog box, the dialog box class destructor automatically calls the CFont destructor to delete the font handle.
The best time to specify the font for any controls in the dialog box is in the OnInitDialog() member function.
The code below demonstrates deriving a dialog box class from CModalDialog and using the SetFont() member function:
Sample Code
/*
* Compiler options needed: None
*/
class CMyAboutBox : public CDialog
{
CFont m_font;
public:
// Constructor -- This code assumes a dialog box
// template named "ABOUTDLG" in the application's .RC file.
CMyAboutBox(CWnd* pParentWnd = NULL) :
CModalDialog("ABOUTDLG", pParentWnd) {};
BOOL OnInitDialog();
};
// OnInitDialog() function -- Called after Windows creates
// the dialog box but before it is painted on the screen.
BOOL CMyAboutBox::OnInitDialog(
{
LOGFONT lf; // Used to create the CFont.
CDialog::OnInitDialog(); // Call default ::OnInitDialog
memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
lf.lfHeight = 20; // Request a 20-pixel-high font
strcpy(lf.lfFaceName, "Arial"); // with face name "Arial".
m_font.CreateFontIndirect(
// Use the font to paint a control. This code assumes
// a control named IDC_TEXT1 in the dialog box.
GetDlgItem(IDC_TEXT1)->Set
return TRUE;
}
ASKER
NawalKishore197:
Yes indeed I do plan to use the SetFont() however as I said:
I have stripped down the code to almost nothing in my attempt to find out why it works in one dialog and not the other. !
In the bare stripped down version the font is created in the OnInitDialog() and destroyed in PostNcDestroy(), the font is NEVER USED and it still causes problems.
I set a break point in PostNcDestroy()
if( m_pFont != NULL )
{
m_pFont->DeleteObject(); // breakpoint here confirms this is called.
delete m_pFont; // does not help however I'm advised it should be here.
}
........
Someone suggested the delete() is the culprit !
Thanks for the feedback: To sum it up. I'm doing exactly what you/the MSDN article says I should...
Yes indeed I do plan to use the SetFont() however as I said:
I have stripped down the code to almost nothing in my attempt to find out why it works in one dialog and not the other. !
In the bare stripped down version the font is created in the OnInitDialog() and destroyed in PostNcDestroy(), the font is NEVER USED and it still causes problems.
I set a break point in PostNcDestroy()
if( m_pFont != NULL )
{
m_pFont->DeleteObject(); // breakpoint here confirms this is called.
delete m_pFont; // does not help however I'm advised it should be here.
}
........
Someone suggested the delete() is the culprit !
Thanks for the feedback: To sum it up. I'm doing exactly what you/the MSDN article says I should...
I don't understand why your code isn't working but just for completeness try the following.
In OnInitDialog, after you create the font add the line
TRACE("OnInitDialog, m_pFont=%ld\n", (long)m_pFont);
and in the PostNCDestroy
CMyDialog::OnPostNcDestroy ()
{
CDialog::OnPostNcDestroy() ; //call base class first to destroy window objects
TRACE("OnPostNcDestroy, m_pFont=%ld\n", (long)m_pFont);
if( m_pFont != NULL )
Compare the TRACE output and confirm the m_pFont values are the same (not that it is somehow getting modified)
In OnInitDialog, after you create the font add the line
TRACE("OnInitDialog, m_pFont=%ld\n", (long)m_pFont);
and in the PostNCDestroy
CMyDialog::OnPostNcDestroy
{
CDialog::OnPostNcDestroy()
TRACE("OnPostNcDestroy, m_pFont=%ld\n", (long)m_pFont);
if( m_pFont != NULL )
Compare the TRACE output and confirm the m_pFont values are the same (not that it is somehow getting modified)
ASKER
Here it is...
OnInitDialog, m_pFont=3698352
OnPostNcDestroy, m_pFont=3698352
Detected memory leaks!
Dumping objects ->
D:\PROJECTS\PC_BT\GPSSetti ngs.cpp(14 6) : {136} client block at 0x00386EB0, subtype 0, 8 bytes long.
a CFont object at $00386EB0, 8 bytes long
Object dump complete.
Line 146 in the code m_pFont = new CFont;
Yet the same Cfont code in another dialog (and for years past ) does not generate this error !
OnInitDialog, m_pFont=3698352
OnPostNcDestroy, m_pFont=3698352
Detected memory leaks!
Dumping objects ->
D:\PROJECTS\PC_BT\GPSSetti
a CFont object at $00386EB0, 8 bytes long
Object dump complete.
Line 146 in the code m_pFont = new CFont;
Yet the same Cfont code in another dialog (and for years past ) does not generate this error !
OK - the pointer isn't being reassigned somehow so that is one possibility less.
You require the delete m_pFont else you have a memory leak (memory assignment with new requires a matching delete somewhere)
The m_pFont->DeleteObject() call however should be redundant. (The CFont destructor calls the DeleteObject function).
You require the delete m_pFont else you have a memory leak (memory assignment with new requires a matching delete somewhere)
The m_pFont->DeleteObject() call however should be redundant. (The CFont destructor calls the DeleteObject function).
ASKER
AndyAinscow:
About delete...
From the Help File
Quote:
CFont::CreateFontIndirect
BOOL CreateFontIndirect(const LOGFONT* lpLogFont );
..
..
// Done with the font. Delete the font object.
font.DeleteObject();
End Quote.
Notice they do not use delete font; !
Perhaps the Help file is wrong... That would not be the first time.
I the meantime I took the suggestion from _mb_ and just used
CFont m_cFont;
VERIFY(m_cFont.CreateFont(
24, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
TEXT("Arial"))); // lpszFacename
That works. It is not the answer to the question but it allows me to carry on with the rest of the code.
However for future work I'd still like to know why old and much used code works several hundreds time in the past, and then comes up with an error.. ! Code should not go "Bump in the night"
About delete...
From the Help File
Quote:
CFont::CreateFontIndirect
BOOL CreateFontIndirect(const LOGFONT* lpLogFont );
..
..
// Done with the font. Delete the font object.
font.DeleteObject();
End Quote.
Notice they do not use delete font; !
Perhaps the Help file is wrong... That would not be the first time.
I the meantime I took the suggestion from _mb_ and just used
CFont m_cFont;
VERIFY(m_cFont.CreateFont(
24, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
TEXT("Arial"))); // lpszFacename
That works. It is not the answer to the question but it allows me to carry on with the rest of the code.
However for future work I'd still like to know why old and much used code works several hundreds time in the past, and then comes up with an error.. ! Code should not go "Bump in the night"
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Erm, thinks.
Did the old code (other dialog) use
CFont m_Font in the header wheras your new dialog uses CFont* m_pFont and an extra line in the OnInitDialog of m_pFont = new CFont;
Did the old code (other dialog) use
CFont m_Font in the header wheras your new dialog uses CFont* m_pFont and an extra line in the OnInitDialog of m_pFont = new CFont;
ASKER
AndyAinscow :
Sorry I was not clear enough: The FIX was to use the suggestion by _mb_ I'll re-write the bit that confused you (sorry)
In the meantime I took the suggestion from _mb_ and just used
CFont m_cFont; // is decalred in the class header therefore it does exist until the CDialog class is destroyed. BTW THIS IS THE FIX Not the problem !
int OnInitDialog()
VERIFY(m_cFont.CreateFont(
24, // nHeight
...
...
Sorry I was not clear enough: The FIX was to use the suggestion by _mb_ I'll re-write the bit that confused you (sorry)
In the meantime I took the suggestion from _mb_ and just used
CFont m_cFont; // is decalred in the class header therefore it does exist until the CDialog class is destroyed. BTW THIS IS THE FIX Not the problem !
int OnInitDialog()
VERIFY(m_cFont.CreateFont(
24, // nHeight
...
...
The bottom line is that you can not delete the font
if it is in use by any winodw or
if it is a System Font.
If the parameter is refer to a System Font, even if you call deleteobject , the HFONT will not get delete.
Use the HFONT or detach it befor closing the dialog.
if it is in use by any winodw or
if it is a System Font.
If the parameter is refer to a System Font, even if you call deleteobject , the HFONT will not get delete.
Use the HFONT or detach it befor closing the dialog.
>>{143} client block at 0x003860B8, subtype 0, 8 bytes long.
Even though you say
>> delete m_pFont; // does not help
you should keep that, this would have been my 1st guess also and indeed seems to be the source of the problem.