Resolved Need to use Resource Embedded font in Application

tim8w

Well-known member
Joined
Sep 8, 2020
Messages
147
Programming Experience
10+
I have a Font that I want my application to use. I have tried MANY suggestions on the web and have not found one that works. I tried embedding the file in the Application's Resources, but could never get that to work. I also tried to get ClickOnce to install the font for me, but also couldn't get that to work. Is this not something very commonly done? Anyway if anyone any suggestions, I would appreciate it.
 
Solution
As you can see from your screenshot, the resource is named "LEDFont", not "LEDFont.ttf". Adding resources the way you have will always drop the file extension.

I'm still not sure that you'll be able to access that resource that way though. You'll probably need to use My.Resources to get a Stream. If you want to use GetManifestResourceStream then I think you'll have to add the file to your project and change its Build Action to Embedded Resource. Not 100% sure about that though.
The above is if you are using GDI.

Below is if you are using DirectWrite:
 
I tried AddFontMemResourceEx but am having problems with the fontStream. It comes back null.

C#:
Expand Collapse Copy
        [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, ref uint pcFonts);

            try
            {
                string resource = "LEDFont.ttf"; // specify embedded resource name

                // receive resource stream
                System.IO.Stream fontStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resource);

                // create an unsafe memory block for the font data
                System.IntPtr data = System.Runtime.InteropServices.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
                System.Runtime.InteropServices.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
                System.Runtime.InteropServices.Marshal.FreeCoTaskMem(data);

                lblTaktTime.Font = new Font(pFC.Families[0], 60, FontStyle.Bold);
            }
            catch (Exception exp)
            {
            }

1755638884654.png


Any ideas?
 
That would suggest that the resource is not named what you think it is. E.g. Line 5 las the wrong value.
 
As you can see from your screenshot, the resource is named "LEDFont", not "LEDFont.ttf". Adding resources the way you have will always drop the file extension.

I'm still not sure that you'll be able to access that resource that way though. You'll probably need to use My.Resources to get a Stream. If you want to use GetManifestResourceStream then I think you'll have to add the file to your project and change its Build Action to Embedded Resource. Not 100% sure about that though.
 
Solution
That would suggest that the resource is not named what you think it is. E.g. Line 5 las the wrong value.
I have tried both "LEDFont" and "LEDFont.ttf" and the results are the same...

Maybe I'm looking at this the wrong way. Is there a way for the ClickOnce installer to install the Font without specifying an absolute path?
 
Last edited:
As you can see from your screenshot, the resource is named "LEDFont", not "LEDFont.ttf". Adding resources the way you have will always drop the file extension.

I'm still not sure that you'll be able to access that resource that way though. You'll probably need to use My.Resources to get a Stream. If you want to use GetManifestResourceStream then I think you'll have to add the file to your project and change its Build Action to Embedded Resource. Not 100% sure about that though.
I would like to do it this way,:

lblTaktTime.Font = new Font(TaktTimeDisplay.Properties.Resources.LEDFont, 60, FontStyle.Bold);

but when you add the Font to the Resource it adds it as a binary (byte[]) type.
 
Use GetManifestResourceNames() to see what the resource compiler actually put into the assembly.

I have a feeling that the string that needs to be passed to GetManifestResourceStream() needs to be "TaktTimeDisplay.Properties.Resources.LEDFont"
 
Use GetManifestResourceNames() to see what the resource compiler actually put into the assembly.

I have a feeling that the string that needs to be passed to GetManifestResourceStream() needs to be "TaktTimeDisplay.Properties.Resources.LEDFont"
I get the following when I use GetManifestResourceNames():

TaktTimeDisplay.frmTaktTimeDisplay.Resources

No Resource name at all, but it's interesting that it adds the Form name. How do I get the actual resource name?

I thought the following code would return each individual Resource name, but it returns TaktTimeDisplay.frmTaktTimeDisplay.Resources for only 2 resources in the assembly I have 6 Images, 1 Icon and one File. The one "File" is the Font File. Its curious that it didn't loop eight times and give me "TaktTimeDisplay.frmTaktTimeDisplay.Resources.SomeName" for each of the eight files...

C#:
Expand Collapse Copy
                System.Reflection.Assembly asmb = System.Reflection.Assembly.GetExecutingAssembly();
                string[] sNames = asmb.GetManifestResourceNames();
                foreach (string s in sNames)
                {
                    System.IO.Stream strm = asmb.GetManifestResourceStream(s);
                    if (strm != null)
                    {
                    }
                }
 
I'm an idiot. Just because the Font was added to the Resources doesn't make it "Embedded". Once I Right-Mouse-Clicked on the the Font in the Project Resources folder and changed the Build Action to "Embedded Resource", then the font showed up in the "GetManifestResourceNames" call...

Thanks for all the suggestions and help.
 
When you add to resources page they are embedded automatically in a .resources file, and code is generated to access them with Properties.Resources.Name
This property will return the data as byte array.
 
I'm not sure, but I think that what @JohnH is driving at is, that it might be possible to pass that byte array directly to AddFontMemResourceEx() directly instead of doing your own marshalling. You might be able to let the compiler do the marshalling for you, as hinted by what is listed in PInvoke.net for that GDI API:
C#:
Expand Collapse Copy
[DllImport("gdi32.dll", ExactSpelling=true)]
private static extern IntPtr AddFontMemResourceEx(byte[] pbFont, int cbFont, IntPtr pdv, out uint pcFonts)


Obviously, you should test to verify.
 
Back
Top Bottom