Classic VB Corner

Honoring Hidden Fonts

Windows 7 hides a number of locale-inappropriate fonts by default, and allows users to toggle this property as well. Here's how to honor that setting.

Remember the old warnings about not loading too many fonts, as they'd slow the system down? Yeah, you probably ignored those too. And later regretted it, at times, as you scanned your font selection dialogs or dropdowns looking for a particular font. You'd probably also wonder, "what are some of those fonts?!?" Happened to me a lot.

Well, Windows 7 now helps, a bit, with this problem by offering what amounts to a Hidden property for fonts. By default, most locale-inappropriate fonts are set to hidden, and users may also toggle this property from the Fonts dialog in Control Panel. Unfortunately, Microsoft chose to not expose any API to this useful property.

This shouldn't be an issue, according to Microsoft, as the common font dialog hides these fonts for you. But if you want to expose a dropdown list of fonts for users to choose from, like, oh, Microsoft Word, well, tough luck. Hmmm, but looking at both Microsoft Word 2007 and 2010, running under Windows 7, and they are at least so far playing by their own rules, it appears. Pull up WordPad, though, and you'll quickly see that the dropdown font list in that applet is somehow detecting which fonts are hidden and which are not.

So how is WordPad making this determination? On a hunch, I fired up Process Monitor (procmon), and started watching the registry changes while I toggled the hidden property of a few fonts on and off. Bingo! It turns out there's a registry entry that holds a list of all the hidden fonts in Windows 7. You can find the "Inactive Fonts" entry under this key:

\HKCU\Software\Microsoft\Windows NT\CurrentVersion\Font Management

This "Inactive Fonts" entry is stored in the REG_MULTI_SZ format, which is just a series (or list) of null-terminated (vbNullChar) strings. This is probably the easiest list to search, of all, as we can leverage the power of VB's native Instr function like so:

Public Function FontHidden(ByVal FontFamily As String, _
  Optional ByVal ForceRefresh As Boolean = True) As Boolean
  
  Static Initialized As Boolean
  Static fnts As String
  Const Key As String = _
   "Software\Microsoft\Windows NT\CurrentVersion\Font Management"
  
  ' If this is the first time this routine has been called, or a
  ' forced refresh is requested, read hidden fonts from registry.
  If Initialized = False Or ForceRefresh = True Then
   fnts = RegGetStringValue _
     (HKEY_CURRENT_USER, Key, "Inactive Fonts")
   fnts = vbNullChar & fnts
   Initialized = True
  End If
  
  ' Registry string is REG_MULTI_SZ, which means it's nullchar
  ' delimited So we bracket search term with nullchars and do
  ' a case-insensitive scan:
  FontFamily = vbNullChar & Trim$(FontFamily) & vbNullChar
  FontHidden = CBool(InStr(1, fnts, FontFamily, vbTextCompare))
End Function

You can use the registry routine of your choice, of course, to snag that string from the system. The one I used will be available with the code download linked below. The function I wrote persists the registry value, rather than call it each time, on the assumption that it will be recalled repeatedly to filter a long list of fonts. But as you can see, I did provide a means to force a refresh of the list of hidden fonts.

The real meat of the FontHidden function is in the very last line where the return value is assigned. Note that when the list of hidden fonts is retrieved, I add a vbNullChar to the beginning of the string. Now, to search the list for a given substring, we simply bracket the search phrase with vbNullChar's and pass both to Instr. To be safe, I chose the case-insensitive vbTextCompare option. If Instr returns a value other than 0, the search string we're looking for matches an element in the list.

You can now call EnumFontFamiliesEx, and filter the results of that to remove all the hidden fonts by comparing the family name passed in each callback to the "Invalid Fonts" list stored in the registry. You can download the FontFilter sample from my Web site, for a completely coded example, if you'd like.

As a final note, I'll add that you may also want to filter out the fonts that begin with an "@" symbol, as these denote vertical fonts (see Figure 10) that are most typically used in Asian systems. It remains a mystery to me why Microsoft chose to return an attribute of the font by altering the font name, in this case, rather than through some identifiable data element. I'm also unsure why one particular font family, "@Kozuka", isn't typically filtered out by the common font dialog, while all others are. If you have any insight on either of those issues, please leave a comment below or drop me an email.

About the Author

Karl E. Peterson wrote Q&A, Programming Techniques, and various other columns for VBPJ and VSM from 1995 onward, until Classic VB columns were dropped entirely in favor of other languages. Similarly, Karl was a Microsoft BASIC MVP from 1994 through 2005, until such community contributions were no longer deemed valuable. He is the author of VisualStudioMagazine.com's new Classic VB Corner column. You can contact him through his Web site if you'd like to suggest future topics for this column.

comments powered by Disqus

Featured

  • Hands On: New VS Code Insiders Build Creates Web Page from Image in Seconds

    New Vision support with GitHub Copilot in the latest Visual Studio Code Insiders build takes a user-supplied mockup image and creates a web page from it in seconds, handling all the HTML and CSS.

  • Naive Bayes Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the naive Bayes regression technique, where the goal is to predict a single numeric value. Compared to other machine learning regression techniques, naive Bayes regression is usually less accurate, but is simple, easy to implement and customize, works on both large and small datasets, is highly interpretable, and doesn't require tuning any hyperparameters.

  • VS Code Copilot Previews New GPT-4o AI Code Completion Model

    The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

  • Microsoft's Rust Embrace Continues with Azure SDK Beta

    "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

  • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

    Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

Subscribe on YouTube

Upcoming Training Events