Take the 2-minute tour ×

The picture below (enlarged, so you better see the differences) shows Font differences between dynamically created Edit controls (the upper two examples) and Edit Controls created from the Dialog Editor (the lower example). How can I make the font of my dynamically created CEdit controls looking like the default (the lower example)?

enter image description here

I have created the CEdit Controls like following:

obj->CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""),
              rect.left, rect.top, rect.Width(), rect.Height(),
              GetSafeHwnd(), reinterpret_cast<HMENU>(mId));

obj->SetFont(&mFont); // mFont was created in the Dialog Constructor
                      // with mFont.CreatePointFont(80, _T("MS Shell Dlg"));

Thanks for your help!

share|improve this question
add comment

1 Answer

up vote 41 down vote accepted

The first example is using the System font (SYSTEM_FONT), as retrieved with the GetStockObject function, which is a bitmap font that has not been used since the days of Windows 3. More information is available on Raymond Chen's blog, and Michael Kaplan's blog.

The second example is using the "MS Shell Dlg" font, just like you asked it to. That actually maps to a font called "Microsoft Sans Serif" or "MS Sans Serif", the UI font back in the days of Windows 95 and 98. This is also known as DEFAULT_GUI_FONT, which indeed used to be an accurate name for it, but alas, it is accurate no longer.

Beginning with Windows 2000 (and continued in XP), Tahoma was used as the default UI font. This is what you are seeing in the third example: Tahoma 8 pt. Unfortunately, even on those operating systems, "MS Shell Dlg" does not return Tahoma--it still returns MS Sans Serif, which is why it looks wrong.

So, you could simply specify Tahoma as the GUI font, but that wouldn't really be correct, because it would break in older versions of the OS where Tahoma isn't installed or supported, or on foreign language versions of the operating system, where a different font is used out of necessity. Instead, you're supposed to specify the DS_SHELLFONT flag, which Raymond talks about here.

And all was fine and good until Windows Vista came out. And in Windows Vista, the powers that be at Microsoft decided that Tahoma was getting a little long-in-the-tooth and Windows was due for another UI font upgrade. They developed their own special font in-house called Segoe UI, supposedly designed for optimum on-screen readability. And in a special little twist, they decided that the default size should now be 9 pt, instead of 8 pt as used by every previous version of the OS, regardless of the font face. And you would probably think that either "MS Shell Dlg", "MS Shell Dlg2", or DS_SHELLFONT (or all three) would get you this new-fangled Segoe UI font, but you'd be wrong.

Uh oh. Now things get tricky... Not only does Vista use a different font than XP that is not easily accessible with a one-size-fits-all identifier, but it also uses a different size, changing the way your dialog will look on those systems, if you can get it to display at all. In many, many places, the Windows shell team appeared to simply punt the challenge--Tahoma 8 pt is used all over the place, even with the Aero theme enabled, when it's supposed to be using Segoe UI 9 pt. This kind of thing really makes the UI look unpolished, and it was the subject of lots of nitpicking back in the early days of Vista. Now, it seems most people have forgotten about it, but the UI hasn't started looking any less scattered and inconsistent.

And you're not the Windows shell team: you can't get away with this in your own app. The Top Rules for the Windows Vista User Experience even state explicitly that you should always:

  • Use Segoe UI, the new Windows Vista system font.
  • Respect the user's settings by always referencing the system font, sizes, and colors using the Windows Theme APIs. Don't use fixed values for fonts, sizes, or colors.

To be honest, I haven't really heard a good solution to this problem yet. And I suspect that by the time I ever do, no one will need to support Windows XP anymore (although most people aren't quite there yet). But here's what I do: I extract the default system font at runtime using the SystemParametersInfo function. Fortunately, the system message box font (lfMessageFont) is the correct font face and size, regardless of the current version of Windows and the user's chosen theme.

My code to initialize windows or dialogs generally looks something like this (SystemInfo::IsVistaOrLater is a helper function I've written; the implementation is the obvious):

// Get the system message box font
ncm.cbSize = sizeof(ncm);

// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
// will be the wrong size for previous versions, so we need to adjust it.
#if(_MSC_VER >= 1500 && WINVER >= 0x0600)
if (!SystemInfo::IsVistaOrLater())
    // In versions of Windows prior to Vista, the iPaddedBorderWidth member
    // is not present, so we need to subtract its size from cbSize.
    ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);

SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
HFONT hDlgFont = CreateFontIndirect(&(ncm.lfMessageFont));

// Set the dialog to use the system message box font
SetFont(m_DlgFont, TRUE);
SendMessage(hWnd, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(FALSE, 0));

Or even easier in MFC, with the handy SendMessageToDescendants method
(m_DlgFont is a CFont object defined for the class):

// Get the system message box font
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
LOGFONT lfDlgFont = ncm.lfMessageFont;

// Set the dialog and all its controls to use the system message box font
SetFont(m_DlgFont, TRUE);
SendMessageToDescendants(WM_SETFONT, (WPARAM)m_DlgFont.m_hFont, MAKELPARAM(FALSE, 0), TRUE);

If you're not using MFC, I highly recommend implementing your own recursive version of SendMessageToDescendants. It makes the initialization code a lot simpler.

share|improve this answer
@Cody The good solution is to use a better framework. Apps built with VCL have no such troubles. –  David Heffernan May 19 '11 at 15:12
@Cody: Many thanks for the detailed explanation, I learned quite a bit. Interesting that those things go back to Windows 3. I've tried your solution but SystemParametersInfo returns MS Sans Serif instead of Tahoma, thus I initialize the font with MS Shell Dlg 2, which is mapped to the Tahoma font (target system not older than windows 2000). One note to SystemParametersInfo: I had to subtract sizeof(ncm.iPaddedBorderWidth) from ncm.cbSize to make it work on my system. –  Christian Ammer May 19 '11 at 18:35
@Christian: Yeah, can you tell I've spent way too much time on this? Props to you for caring about how your controls look and getting them to fit in with the platform's default styling. Too few developers pay attention to this. Things go back much further than Windows 3; large portions of the Win32 API are unchanged (at least in spirit) since Windows 1.0. Backwards compatibility is a very demanding mistress. The only way that the code I've shown (using SystemParametersInfo and NONCLIENTMETRICS.lfMessageFont) would return MS Sans Serif is if that's set as your Windows font in the... –  Cody Gray May 20 '11 at 3:27
@Christian: That all makes sense, but your conclusion isn't quite right. And I'm a stickler for details (in case you couldn't tell). The default "Windows Classic" theme (called "Windows Standard") does in fact use the Tahoma font as the message box font. The other pre-defined color schemes, however, do not, as they have not been updated since they were first released in Windows 95/98. Regardless, though, if MS Sans Serif is the message box font in the Appearance theme, it's what all of the native controls are going to be displayed in. If you want to match them, you must use it, too. –  Cody Gray May 20 '11 at 9:13
@dccarmo stackoverflow.com/questions/8296784/… –  David Heffernan Feb 22 '13 at 15:22
show 5 more comments

Your Answer


