Thread: HDC and HFONT

  1. #1
    Registered User
    Join Date
    Jun 2010
    Posts
    24

    HDC and HFONT

    I'm curios as to why this

    Code:
    void initialize_font(HFONT hf, HWND hwnd) {
    	HDC hdc;
    	TEXTMETRIC tm;
    	hdc = GetDC(hwnd);
    	hf = CreateFont(20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Times New Roman");
    	SelectObject(hdc, hf);
    	GetTextMetrics(hdc, &tm);
    	printf("Char Height is %d Average Char Width is %d\n", tm.tmHeight, tm.tmAveCharWidth);
    }
    results in a different average character width to this

    Code:
    void initialize_font(HFONT hf, HWND hwnd) {
    	HDC hdc, hdc2;
    	TEXTMETRIC tm;
    	hdc = GetDC(hwnd);
    	hdc2 = GetDC(hwnd);
    	hf = CreateFont(20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Times New Roman");
    	SelectObject(hdc, hf);
    	GetTextMetrics(hdc2, &tm);
    	printf("Char Height is %d Average Char Width is %d\n", tm.tmHeight, tm.tmAveCharWidth);
    }
    I understand that each call to GetDC() will result in a different handle to the device context getting returned but shouldn't the handles both be pointing to the same client area and so have the same text metrics?
    Last edited by Golf7; 03-20-2013 at 07:39 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Perhaps you should try actually drawing some text using both device contexts, so you can see the difference.

    > GetTextMetrics(hdc2, &tm);
    Because it seems to me that this just returns whatever the default font of the dc is, before you would call selectObject with a new font.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    To add to Salem's answer...

    Think of a HDC as a structure. It contains a full set of default GDI objects when created or 'got' (GetDC), these include a FONT, PEN, BRUSH, etc

    You changed the FONT in one HDC and not the other, so there should be a difference (unless the FONT you changed too was the same as the default FONT).

    BTW You have a number of GDI leaks.
    PCs have a very limited amount of GDI memory. Try adding GDI Objects to the items displayed in TaskManager and see how many you are leaking.

    .NET compilers treat GDI objects as 'default' and will garbage collect them (at some point), but your code is just bad practice/form.

    If you create a GDI object you should DeleteObject(), but DeleteObject() may not work while the GDI object is selected in a DC.

    So if you use SelectObject() to change a GDI object in a DC you should catch the returned GDI object and SelectObject() this default GDI back into the DC so you can clean up both the GDI you created and the DC.

    To clean up a DC you 'got' from GetDC() you should call ReleaseDC() (once you have returned the default GDI objects).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  4. #4
    Registered User
    Join Date
    Jun 2010
    Posts
    24
    Now I understand what an HDC is, I can see that it will cause a leak in the above code as hdc is local to the function and so not accessible once the function returns. The font in question though is to be used throughout the life of the program, so do I really have to CreateFont() and DeleteObject() every time I want to use it rather than just deleting at the end of the program?
    Last edited by Golf7; 03-21-2013 at 09:06 AM.

  5. #5
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    I cannot answer as I do not have enough info on how your app works.

    Generally you create a memory DC when the app starts (with global scope), with its own bitmap and collection of GDIs (pen, brush, font, etc).
    When the app closes you put the default GDIs back and clean up the GDIs you got or created.

    When you need to draw to the screen you draw to this memory DC and generate a paint message.
    Your paint handler then copies (BitBlt()) your memory DC to the screen DC from the PAINTSTRUCT filed in the BeginPaint().

    If for some reason you only need a font...

    Give the font global scope.
    When you need to use it.
    Code:
    //witten from memory, not compiled....
    
    //get the screen DC
    HDC hdc = GetDC(NULL);
    //select in the global font
    HFONT *defaultFont = (HFONT*)SelectObject(hdc, globalFont);
    
    //write text
    
    //clean up
    //put the DC back to default state
    SelectObject(hdc, defaultFont);
    //now release the DC
    ReleaseDC(hdc);
    NOTE: This should not be done in the WM_PAINT handler!
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Writing a HFONT to file.
    By switchcase in forum Windows Programming
    Replies: 6
    Last Post: 10-12-2007, 09:42 PM
  2. Copying HFONT
    By Smallz in forum Windows Programming
    Replies: 2
    Last Post: 08-31-2006, 01:45 AM