When I send a WM_GETFONT message to a window, why don’t I get a font?

A customer reported that the WM_GET­FONT message was not working. Specifically, they sent the message to a window, and they can plainly see that the window is rendering with a particular font, yet the WM_GET­FONT message returns 0. Why isn’t the window returning the correct font handle?

The WM_SET­FONT and WM_GET­FONT messages are not mandatory. A window may choose to support them, or it may choose not to, or it may even choose to support one but not the other. (Though if it supports WM_SET­FONT, it probably ought to support WM_GET­FONT.)

For example, our scroll bar program creates a custom font for the items in the list, but it does not implement the WM_SET­FONT or WM_GET­FONT messages. If you try to change the font via WM_SET­FONT, nothing happens. If you ask for the font via WM_GET­FONT, you get nothing back.

A control might ignore your attempt to change the font if it already has its own notion of what font it should be using. Or maybe the control shows content in multiple fonts, so the concept of “the” font does not map well to the render model. (What would WM_GET­FONT on an HTML control return?) Or maybe the control doesn’t use GDI fonts at all. (Maybe it uses Direct­Write.)

That’s one of the reasons why the rules for the WM_SET­FONT are set up the way they are. Since there is no way to tell whether a window did anything in response to the WM_SET­FONT message, there would be no way to know whether responsibility for destroying the font should be transferred to the control or retained by the caller.

Controls that are designed to be used in dialog boxes are the ones most likely to support the WM_SET­FONT message, since that’s the message the dialog manager uses to tell each control the font specified in the dialog box template. The hope is that all of the controls will respect that font, so that the controls on the dialog box have a consistent appearance. But there’s nothing preventing a control from saying, “Screw you. I’m drawing with OCR-A and there’s nothing you can do to stop me.”

Comments (12)
  1. Juan says:

    This is another example where some engineers thinks software engineering is a democracy where in reality is a technocracy. The result a poor designed system that looks inconsistent even to developers.

  2. 12BitSlab says:

    There are good reasons why some controls don't respect WM_SETFONT.  I have seen controls that used the Wingdings font in order to embellish the appearance of the control.  Those controls SHOULD ignore WM_GET/SETFONT.  With respect to these two messages, I think they are designed exactly the way they should be.

  3. T. West says:

    Thank you for that last line.  I got my chuckle of the day.

  4. Timothy Byrd (ETAP) says:

    @Juan – How would you design it better?

  5. Cheong says:

    @12BitSlab: I'm partially disagree with you. While it make sense for the WM_SETFONT part, if the control supports WM_COPY, maybe it'd be good to support some way that allow the copying application know you're using Wingdings.

  6. Karellen says:

    @cheong00: In that case, the control should be using codepoints from the Unicode blocks "Dingbats"[0] and "Ornamental Dingbats"[1] to display the characters, rather than overloading existing characters. It's not the '90s any more!

    [0] en.wikipedia.org/…/Dingbats_(Unicode_block)

    [1] en.wikipedia.org/…/Ornamental_Dingbats

    [Not all Wingdings are mapped to Unicode. For example, the Windows flag logo (position 255) is not in Unicode. -Raymond]
  7. 12BitSlab says:

    @cheong00, You raise a very good point and for the life of me, I can't find a way to disagree with you.  Thanks!

  8. Mark Ransom says:

    Raymond, Unicode has specific blocks just for non-standard characters. According to Wikipedia the Windows flag is often mapped to U+F000. And you'd be surprised at what makes it into Unicode – the latest update includes the Vulcan "live long and prosper" sign.

    [The flip side is that if a button intends to show the Windows logo, and then it gets put inside a dialog box, and the dialog box does a WM_SETFONT to tell the control to get with the font program, your Windows logo is now showing up in the wrong font (and will probably be an ugly black box). This can get particularly nasty if the control is, say, a scroll bar. The up/down arrows are now ugly black boxes. (I don't even want to think what happens if the control is a Web browser.) -Raymond]
  9. Juan says:

    @Timothy Byrd (ETAP) I would force all controls to take care of WM_GET/SETFONT. In fact I would force all controls to subclass a basic class that would take care of it. Why? Consistence. UI is a very serious feature. Users like to have a consistent experience. Non technical users expend a lot of time to learn the shell to be screwed up. So if you don't override those messages you'd get the standard shell font that the user like the most. So I'd make users and others developers happy.

    [How do you force a control to use the font passed to WM_SETFONT? Do you fail all attempts to call SelectObject on the paint DC with some other font? (GDI would say "Hey, don't drag me into your little argument. I just render with whatever font you tell me.") That wouldn't stop programs that use double-buffering. It would also make all Word documents look pretty boring. ("Sorry, you can't change your document font. You have to use the system font.") -Raymond]
  10. Erik F says:

    @Juan: Why? Whst font is a cat picture, and does changing the font change the picture to a dog picture?

  11. Joshua says:

    [It would also make all Word documents look pretty boring.]

    /me wonders why anybody would pass WM_SETFONT to the top-level Word window EVER. (Obviously Word would not pass WM_SETFONT to its editor pane).

    [Somebody embeds a Word document in a dialog box. Dialog boxes send WM_SET­FONT to all child windows so that the controls on the dialog have a consistent font. -Raymond]
  12. Marc K says:

    [How do you force a control to use the font passed to WM_SETFONT?]

    You may not be able to force a control to support WM_SETFONT, but having DefWindowProc support WM_GETFONT might be possible.  The problem with messages like WM_GETFONT, WM_PRINTWINDOW and WM_COPY being the responsibility of the window is that many developers don't know that or don't want to put in the effort to support them.

    [I guess DefWindowProc could implement it by stashing the font handle and regurgitating it in WM_GETFONT, and the control is expected to send itself a WM_GETFONT to find out what font to use. But you're still requiring the control to do something special, so all you did was change "respond to WM_GETFONT and WM_SETFONT" to "send WM_GETFONT when painting". (And how can DefWindowProc implement WM_COPY automatically?) -Raymond]

Comments are closed.