Question

I've run into problems on numerous occasions of users not having one of the Windows Core fonts installed on their machine (Courier New, Comic Sans MS, Arial for example). Whenever I try to construct one of these it throws an error rather than falling back onto a related, or really, any other font.

What is the best way to construct a Font if I'd like it to be Courier, but I'm not particularly wedded to it?

Was it helpful?

Solution

You can embed the fonts as resources and use the unsafe keyword (and must be compiled with 'unsafe') to obtain the fonts... Here's an example code that I used to set a user control to the font of type 'OCR'

private PrivateFontCollection pfc = new PrivateFontCollection();
private Font _fntOCRFont = null;
private enum FontEnum{
   OCR = 0
};

That declares a private collection of fonts...the font 'OCR' is embedded as a resource using the naming convention where 'foo' is a namespace, hence the resource name would be 'foo.ocraext.ttf'...Look at 'InitOCRFont' here which loads the font and adds it to the collection:

private void InitOCRFont(){
   try{
      System.IO.Stream streamFont = this.GetType().Assembly.GetManifestResourceStream("foo.ocraext.ttf");
      if (streamFont != null){
          byte[] fontData = new byte[streamFont.Length];
          streamFont.Read(fontData, 0, (int)streamFont.Length);
          streamFont.Close();
          unsafe{
                fixed(byte *pFontData = fontData){
                   this.pfc.AddMemoryFont((System.IntPtr)pFontData, fontData.Length);
                }
          }
      }else{
          throw new Exception("Error! Could not read built-in Font.");
      }
   }catch(Exception eX){
      throw new Exception("InitOCRFont Method - Exception occurred!\nException was: " + eX.Message);
   }
}

In here, I set the controls within the User control to set the font to that 'OCR' font by iterating through the collection, see 'InitializeCtlFont', font size is 10 and is a bold 'type-face':

private void InitializeCtlFont(){
    this._fntOCRFont = new Font(this.pfc.Families[0], 10.0F, System.Drawing.FontStyle.Bold);
    if (this._fntOCRFont != null){
         foreach(Control ctl in this.Controls){
            if (ctl != null && ((ctl is Label) || (ctl is TextBox))){
                        ctl.Font = this._fntOCRFont;
                    }
         }
    }
}

When the user control gets disposed, it is imperative to free up the resources occupied by the font as shown here in the Dispose method:

try{
   if (this._fntOCRFont != null) this._fntOCRFont.Dispose();
}catch{
}
try{
   if (this.pfc != null) this.pfc.Dispose();
}catch{
}

Hope this helps, Best regards, Tom.

OTHER TIPS

Well, you could use FontFamily.GenericMonospace to get a Monospace font, instead of specifically Courier:

Font f = new Font(FontFamily.GenericMonospace, 12, FontStyle.Regular);

There are a few more such generic font families as well.

You can also use this as a last resort after trying your preferred font and running into an exception.

This is very unusual. The Windows font mapper will always provide a substitute font when your program requests a font that isn't available on the target machine. That substitute font will usually be Microsoft Sans Serif on XP, Segoe UI on later versions. Neither of those should ever cause a problem.

Then again, if the machine is so messed up that it doesn't have the core fonts available, it might have no TrueType font available at all. Yes, that will bomb your program. Frankly, this isn't something you should have to deal with, unless this is a really valuable customer. It is otherwise trivially solved by your customer's support team.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top