11

I'm embedding a font in my windows forms application as embedded resource, and want to use it in a TextBox.

The help of AddMemoryFont() says I have to set compatible text rendering to true in order to use GDI+, and so my font can then be used. But somehow it just won't display the right font.

In Program.cs I explicitly state:

Application.SetCompatibleTextRenderingDefault(true);

So why is it not working? Anybody got a clue on how to set a custom font to a TextBox?

sɐunıɔןɐqɐp
  • 3,332
  • 15
  • 36
  • 40
Led
  • 2,002
  • 4
  • 23
  • 31

2 Answers2

31

Okay, I figured it out thanks to the interwebs and Google.

For future reference, if anybody has this problem, the fix is : after getting your embedded font as a stream, and before calling AddMemoryFont, you have to call AddFontMemResourceEx ! (Not available in C# so you have to import it :

    [DllImport("gdi32.dll")]
    private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);

and then :

            //create an unsafe memory block for the data
        System.IntPtr data = Marshal.AllocCoTaskMem((int)fontStream.Length);
        //create a buffer to read in to
        Byte[] fontData = new Byte[fontStream.Length];
        //fetch the font program from the resource
        fontStream.Read(fontData, 0, (int)fontStream.Length);
        //copy the bytes to the unsafe memory block
        Marshal.Copy(fontData, 0, data, (int)fontStream.Length);

        // We HAVE to do this to register the font to the system (Weird .NET bug !)
        uint cFonts = 0;
        AddFontMemResourceEx(data, (uint)fontData.Length, IntPtr.Zero, ref cFonts);

        //pass the font to the font collection
        mFontCollection.AddMemoryFont(data, (int)fontStream.Length);
        //close the resource stream
        fontStream.Close();
        //free the unsafe memory
        Marshal.FreeCoTaskMem(data);

And presto, you'll be able to use the font. Without the AddFontMemResourceEx it wont work.

Led
  • 2,002
  • 4
  • 23
  • 31
  • Where is "fontStream" coming from here? – Mike Fulton Feb 02 '16 at 03:58
  • 1
    you can create your stream from resources. You should add your font to your project resources then convert it to stream like this: `Stream fontStream = new MemoryStream(Properties.Resources.Font);` – Ege Aydın Jul 28 '16 at 11:51
  • This seems like it would be a great solution. I'm creating a custom control and trying to embed 2 custom fonts in the font's collection that I have. Where does `mFontCollection` come from and how is that used? I hoping in the end to have a property in my control that I can choose a font from as normal (with the exception that it has two new fonts). Ex: `private Font m_FontFace = UserControl.DefaultFont; public Font FontFace { get { return m_FontFace; } set { m_FontFace = value; } }` – Arvo Bowen Dec 08 '16 at 22:49
  • There is a similar and full code over there (for missing parts): https://cboard.cprogramming.com/csharp-programming/147926-font-embedding-textbox.html – Furkan Ekinci Aug 26 '17 at 00:13
  • This seems working, if you use the FontFamily[0] to create a Font-Object. But if you use the FamilyName in the font constructor i always get Microsoft Sans Serif font. Question is: It is possible to create font by FamilyName? – Saftpresse99 Feb 21 '19 at 09:34
  • One can completely skip the code for FontStream when using the Font as embedded resource in the application. Just add the Font to the project's resources, and it will already be available as `byte[]` for you to use it in place of that `Byte[] fontData` variable in this answer. Just type Resource. in your WinForms application. Now you just have to register the `byte []` font data as in this answer. – sɐunıɔןɐqɐp May 18 '21 at 15:37
2

Thanks it's working. TO Embed Font in c# Windows Application

[DllImport("gdi32.dll")]
private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts);

    PrivateFontCollection pFC = new PrivateFontCollection();

        try
        {
            string[] resource = { "newFont-Bold.ttf", "newFont-Regular.ttf" }; // specify embedded resource name

            foreach (var item in resource)
            {
                // receive resource stream
                Stream fontStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(item);

                // create an unsafe memory block for the font data
                System.IntPtr data = Marshal.AllocCoTaskMem((int)fontStream.Length);

                // create a buffer to read in to
                byte[] fontdata = new byte[fontStream.Length];

                // read the font data from the resource
                fontStream.Read(fontdata, 0, (int)fontStream.Length);

                // copy the bytes to the unsafe memory block
                Marshal.Copy(fontdata, 0, data, (int)fontStream.Length);

                ///IMPORTANT line to register font in system
                uint cFonts = 0;
                AddFontMemResourceEx(data, (uint)fontdata.Length, IntPtr.Zero, ref cFonts);

                // pass the font to the font collection
                pFC.AddMemoryFont(data, (int)fontStream.Length);

                // close the resource stream
                fontStream.Close();
                // free up the unsafe memory
                Marshal.FreeCoTaskMem(data);
            }
        }
        catch (Exception exp)
        {
            Log.Error(exp);
        }

        return pFC;
PPr
  • 81
  • 4