C# : Using an embedded font on a textbox
Asked Answered
S

2

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?

Stormproof answered 23/12, 2009 at 22:18 Comment(0)
S
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.

Stormproof answered 24/12, 2009 at 0:10 Comment(6)
Where is "fontStream" coming from here?Aciniform
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);Lashley
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; } }Geneva
There is a similar and full code over there (for missing parts): cboard.cprogramming.com/csharp-programming/…Tedium
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?Sporocyte
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.<FONTNAME> in your WinForms application. Now you just have to register the byte [] font data as in this answer.Potash
R
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;
Roughhouse answered 7/1, 2020 at 4:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.