Update: See this post for a sample implementation in WPF.
Have you ever wondered how to access the various font colours and styles found throughout Windows, such as that of the ‘Main Instruction’ text in the Task Dialog shown above?
If you are using WPF, the SystemFonts class might sound promising at first. However, this class only exposes the following: the icon font, caption font, small caption font, menu font, message font and status font. These aren’t very exciting – in fact, they are all simply 9pt Segoe UI in Windows Vista/7 Aero. (Aside: early Windows 8 builds use 11pt Segoe UI Semilight as the caption (and small caption) font.) For those using Win32 directly, the SystemFonts class wraps around the SystemParametersInfo function (specifically with the messages SPI_GETNONCLIENTMETRICS and SPI_GETICONTITLELOGFONT) the GetThemeSysFont function.
MSDN offers some guidance on default fonts and colours in Windows Vista/7: apparently ‘Main Instruction’ text is 12pt #003399 Segoe UI. This table, while helpful, is not comprehensive, and in general it’s not a good idea to hard-code this kind of thing, as themes/visual styles are liable to change.
The keys lie in the Visual Styles APIs, introduced in Windows XP. In particular, the GetThemeFont function and GetThemeColor function (with the TMT_TEXTCOLOR property identifier), both found in UxTheme.dll. We simply need to specify the ‘part and state’ of the control in question (these are defined in Vsstyle.h and Vssym32.h). ‘Main Instruction’ text, for example, is referenced by the TEXT_MAININSTRUCTION part in the TEXTSTYLE class.
Regrettably, visual styles APIs only work when visual styles are enabled (who’d have thought it?). That is to say, we can’t rely on them with classic themes (Windows Classic and the High Contrast themes).
I emailed the very knowledgeable Larry Osterman about this, and he was kind enough to respond:
AeroStyle.xml tells which metrics to ask for which theme parts (for the OS that matches the version of the SDK it’s in), but there’s no theme API support for classic modes.
Basically they get the metric they’re looking for from the AeroStyle.xml file.
AeroStyle.xml is included in the latest versions of the Windows SDK. It contains the same classes and parts and states mentioned earlier in an XML format. The ‘MainInstruction’ part in the ‘TextStyle’ class looks like this, for instance:
1 2 3 4 5 6 7 8 9 10 11 |
<class name="TextStyle"> <part name="MainInstruction"> <caption> <TextColor>0 51 153</TextColor> <Font>Segoe UI, 12, Quality:ClearType</Font> <ClassicValue type="TextColor">WindowText</ClassicValue> <ClassicValue type="Font">CaptionFont</ClassicValue> </caption> </part> ... </class> |
Of interest are the ‘ClassicValue’ elements. When visual styles are disabled, it seems that ‘Main Instruction’ text uses the caption font (8pt bold Microsoft Sans Serif, as it happens).
In closing: you can use GetThemeFont and GetThemeColor if visual styles are enabled, but you will need look at AeroStyle.xml and hard-code the classic theme fall-back values.
I’d like to see some actual functional code using GetThemeFont. The web is littered with articles/posts pointing to that function but there isn’t any functional code to be found anywhere.
And for anyone that stumbles across this post hoping to find a solution to the visualstyle font problem, here’s a test for the managed approach, showing that the framework cannot get the font info for a single VisualStyleElement
https://gist.github.com/1219126
This is a flaw either with the GetThemeFont API method, or the framework (most likely the former)
See the follow-up post.