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'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


  • VS Code Java Team Details 5 Best Dev Practices

    Microsoft's Visual Studio Code team for Java development added a new Coding Pack for Java installer and detailed best practices for setting up a development environment.

  • Binary Classification Using PyTorch: Defining a Network

    Dr. James McCaffrey of Microsoft Research tackles how to define a network in the second of a series of four articles that present a complete end-to-end production-quality example of binary classification using a PyTorch neural network, including a full Python code sample and data files.

  • Blazor Debugging Boosted in .NET 5 RC 2

    In highlighting updates to ASP.NET Core in the just-launched second and final Release Candidate of .NET 5, Microsoft pointed out better debugging for Blazor, the red-hot project that allows for C# coding of web projects.

  • Block Stack

    Final Go-Live .NET 5 Release Candidate Ships Ahead of Nov. 10 Debut

    Having been deemed "feature complete" and "near final" and "go live" for some time now, .NET 5 is out in a second and final Release Candidate, scheduled for a Nov. 10 debut during .NET Conf 2020.

  • Edge Browser Dev Tools for VS Code Now Generally Available

    Microsoft has moved its Edge browser development tools for Visual Studio Code from preview to general availability, providing in-editor web site debugging and other functionality.

Upcoming Events