Preview Uninstalled Fonts
Q. Load Uninstalled Fonts
A. Well, lemme tell ya, this one nearly wrecked my brain! <g> The short answer is, you cannot use uninstalled fonts. But you can use a trick: Install the font temporarily and avoid telling other applications you've done so (see Figure 1).
Normally, you install a TrueType font by using AddFontResource to add the specified file to the Windows font table. This makes the font available to all applications, but they won't know that unless they ask (using EnumFonts or EnumFontFamilies). A standard install would broadcast WM_FONTCHANGE to alert all running apps of the new font. You want to avoid this step in a preview situation. Finally, a standard install would also write information to the Registry to ensure the install is persisted between sessionsagain, a step to avoid when you simply want to preview a font. You'll skip these steps in the temporary-install technique.
Adding a font file to the Windows font table is the easy part. The task gets tricky in determining whether a given font file is installed already. After all, you want to call RemoveFontResource immediately upon finishing with the font, but to do that against an already installed font wouldn't thrill your users. Unfortunately, AddFontResource offers no hints either, happily reporting success when asked to install an already installed file.
The simplest way to tell if a desired font is available is to ask for it and see if you get it. Create a new StdFont object and assign the desired facename to this object's Name property. The object's Name property returns the assigned facename if the font is available:
What could be simpler? Only catch is, how do you know what facename to use? You can obtain the complete technical TrueType font (TTF) file specifications from the Microsoft Typography Web page (see Resources). (My most sincere thanks to Mathias Schiffer, VB MVP, for his help in decoding these!) TTFs are incredibly information-rich files, but finding the information you seek can be daunting at first. Complicating matters further, TTFs use the Motorola chip's preferred "big-endian" byte ordering, which forces you to reverse everything to restore Intel-formatted "little-endian" sanity (see Resources).
TTFs start with a general header that includes the number of tables within, followed by a brief description of each data table that includes its starting offset. Their descriptor layout resembles DBFs' internal structure in this regard. The OffsetTable begins at the first byte and tells you how many table directory entries follow. Each table directory entry identifies itself with a Tag element, provides a checksum for the referenced table, and offers the offset within the file and the length of the table (find the structure definitions in the CFontPreview.cls file or read them in Listing 1).
Pay attention to three of the TTF tables: name, head, and OS/2. The "name" table is foremost because it provides the elusive facename you need to use the contained font once it's installed. The "head" table includes a magic number you can use to confirm you're actually examining a TrueType file, and the "OS/2" table includes an assortment of useful and interesting font metrics.
Declare an array of TableDirectory structures and populate them all with a single Get statement. Iterate this array, looking for the "head" table to confirm file validity. If the file is valid, start another loop through the table directories and look for the "name" and "OS/2" tables. Use the table offset within the table directory to Get the correct structure directly.
The "name" table consists of NameRecord structures that point to resources such as FamilyName, SubFamilyName, Copyright, Trademark, and others. These vary frequently by platform, with Macintosh and Windows each having unique values, and by language using LocaleID to differentiate. The easiest thing to do is cache all the values within a persistent array so you can reference them at any time without trudging through the file again. Likewise, a persisted WindowsMetrics structure tells you whether to use attributes such as Bold or Italics with the created font (see Listing 1; see Table 1).
I've wrapped up most of this functionality in a class, CFontPreview, that you can drop right into your projects. The internal GetFaceName method determines whether the requested font file is installed already and chooses which of three possible facenames will work to create a new font.
CFontPreview removes temporarily installed fonts in the Class_Terminate event (don't try this strategy if you plan to migrate this code to .NET), making it worry-free from the object-consumer perspective. Note that calling RemoveFontResource only triggers the uninstall. The font remains in Windows' font table until it's selected out of any device contexts in which it had been used.
I'm sure you're either saying to yourself that there's no way you're going back to twiddling bits at this level, or you simply can't wait to try this out. My hunch is the latter.
Karl E. Peterson is a GIS analyst with a regional transportation planning agency and serves as a member of the Visual Basic Programmer's Journal Technical Review and Editorial Advisory boards. Online, he's a Microsoft MVP and a section leader on several VBPJ forums. Find more of Karl's VB samples at www.mvps.org/vb.