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

  • IDE Irony: Coding Errors Cause 'Critical' Vulnerability in Visual Studio

    In a larger-than-normal Patch Tuesday, Microsoft warned of a "critical" vulnerability in Visual Studio that should be fixed immediately if automatic patching isn't enabled, ironically caused by coding errors.

  • Building Blazor Applications

    A trio of Blazor experts will conduct a full-day workshop for devs to learn everything about the tech a a March developer conference in Las Vegas keynoted by Microsoft execs and featuring many Microsoft devs.

  • Gradient Boosting Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the gradient boosting regression technique, where the goal is to predict a single numeric value. Compared to existing library implementations of gradient boosting regression, a from-scratch implementation allows much easier customization and integration with other .NET systems.

  • Microsoft Execs to Tackle AI and Cloud in Dev Conference Keynotes

    AI unsurprisingly is all over keynotes that Microsoft execs will helm to kick off the Visual Studio Live! developer conference in Las Vegas, March 10-14, which the company described as "a must-attend event."

  • Copilot Agentic AI Dev Environment Opens Up to All

    Microsoft removed waitlist restrictions for some of its most advanced GenAI tech, Copilot Workspace, recently made available as a technical preview.

Subscribe on YouTube