-
Strange behaviour
Look at this Function I made:
Code:
BOOL SetWFont( HWND handle, UINT winIdent, UINT fontSize, LPSTR fontFamily )
{
HFONT hFont;
HDC hdc;
long lfHeight;
hdc = GetDC(handle);
lfHeight = -MulDiv(fontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(handle, hdc);
hFont = CreateFont(lfHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fontFamily);
if(!SendDlgItemMessage(handle, winIdent, WM_SETFONT, (WPARAM)hFont, TRUE)) return 0;
hFont = CreateFont(lfHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fontFamily);
DeleteObject(hFont);
return 1;
}
You notice the second call of CreateFont? It's completely unneccessary, you mean? Well, if you ask me, I'd say the same. BUT. Without this line the function doesn't work. It just does nothing if I cut this unlogical 2nd call of CreateFont. And now I'm wondering why!
Has anybody an idea? (well it's not that serious cause the function now works and does what I want, but I think it's strange nevertheless!)
Pry
-
SendMessage with a WM_SETFONT does not return a value.
If you create a font and then create another, over the top of the first without DeleteObject()'ing it, as you are doing, you have created a GDI memory leak.
The best way to do this is with a global HFONT, or a static HFONT in the main callback.
Create the font as the app starts up,
call the setfont at WM_INIT / WM_CREATE
clean the font up at the WM_CLOSE (when the app exits).
-
Mh yeah you're right and I'm going to do it the way you suggested... but can you maybe explain to me why the code without this erroneous line (the 2nd call of createfont), doesn't work?
Thanks so far,
Pry
-
Not an expert with CreateFont, but think I can see your problem.
You are calling CreateFont twice, thus creating two instances of HFONT , but calling DeleteObject only once. Wouldn't this result in a leak?
Therefore, it maybe for your function SetWFont to be effective, an instance of HFONT must remain existence. You in advertently seem to do this by leaving a leaked HFONT instanced.
-
Yeah but novacain mentioned that allready. I'm not quite sure u understood me right :P
Once again:
If I leave the 2nd call of CreateFont in the source (what is a bad thing cause it causes a mem leak, but apart from that) the whole stuff does what it should: changing the font of the control.
Of course I have to change that so it doesn't leak any more.
But the strange thing is when I delete the second call of CreateFont (that doesnt make sense anyway!!!) the function does nothing any more!
Here the code to make things clear:
Code:
BOOL SetWFont( HWND handle, UINT winIdent, UINT fontSize, LPSTR fontFamily )
{
HFONT hFont;
HDC hdc;
long lfHeight;
hdc = GetDC(handle);
lfHeight = -MulDiv(fontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(handle, hdc);
hFont = CreateFont(lfHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fontFamily);
if(!SendDlgItemMessage(handle, winIdent, WM_SETFONT, (WPARAM)hFont, TRUE)) return 0;
DeleteObject(hFont);
return 1;
}
This function doesn't work! I was playing around and accidentially added the second call of CreateFont. And then it worked and I went "huh???" and posted it here.
So... what do you think?
-
I think the if() on a SendMessage() that has no return will create some undefined behaviour, so I don't know why.
I forgot to mention that the HFONT may have to be global or static. If it is local it will loose scope once the function exits. I am not sure if the HFONT must remain valid for the entire apps execution or if it is stored and so can be local.
Davros
>>Therefore, it maybe for your function SetWFont to be effective, an instance of HFONT must remain existence. You in advertently seem to do this by leaving a leaked HFONT instanced.<<
Davros's opinion that the second call to CreateFont() causes a leak of the HFONT, which allows the SetFont() HFONT to be used, is my guess as well.
-
-
Your function shouldn't work! You forgot to select it into the HDC.
That is imperative. Also you should know that when you DO select it with SelectObject(), that function will return a handle to the previous font, should you wish to restore it later.
ie:
Code:
HFONT font = CreateFont( 25, 15, 0, 0, FW_EXTRABOLD, 0, 0, 0, ANSI_CHARSET, 10, PROOF_QUALITY, VARIABLE_PITCH, FF_ROMAN, "courier");
HFONT previous = (HFONT)SelectObject(hdc, font);
Try this:
Code:
HFONT SetWFont( HWND handle, UINT winIdent, UINT fontSize, LPSTR fontFamily )
{
HFONT hFont;
HDC hdc;
long lfHeight;
hdc = GetDC(handle);
lfHeight = -MulDiv(fontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
hFont = CreateFont(lfHeight, 20, 0, 0, 0, 0, 0, 0, ANSI_CHARSET,10, PROOF_QUALITY, VARIABLE_PITCH, FF_ROMAN, fontFamily);
SelectObject(hdc, hFont);
ReleaseDC(handle, hdc);
return hFont;
}
-
Well thanks, I figured it out now :D
Pry
-
Ahhh...Sebastiani
He does not have to select the font into a DC, he just needs the handle to the font (look at FillRect(), FrameRect() as examples with brushes used but not selected into a DC).
In fact your code is a memory leak.
You have lost the original font in the DC.
You have returned a local variable that will loose scope as soon as the function ends.
Also the new font may not be able to be deleted successfully as you have left it in a DC and DeleteObject() will not work on an object still selected into a DC. (the only way to get it out is to create another and SelectObject() it in, and so on)
(You say, very correctly, that you must conserve the return from SelectObject() then give an example where you don't??)
-
well I "solved" the problem by making hFont global, creating the font using the function I showed u without the DeleteObject() and deleting it finally during the processing of the WM_DESTROY message.... is this still a mem leak this way?
-
When you use SelectObject() the return is the GDI object already in the DC. You can not delete a GDI object while it is selected into a DC.
As you are not selecting it into a DC it should not cause a problem. If concerned check the return from the DeleteObject() and call GetLastError() if there is a problem.