1

I need to add a set of fonts to PrivateFontCollection. For some reason this task should be accomplished by using AddMemoryFont function.

    var fontCollectionFromMemory = new PrivateFontCollection();
    var fontCollectionFromFile = new PrivateFontCollection();
    foreach (var file in Directory.GetFiles(@"C:\Windows\Fonts", "*.ttf"))
    {
        using (var stream = File.OpenRead(file))
        {
            var fontData = new byte[stream.Length];
            stream.Read(fontData, 0, fontData.Length);
            var fontDataPtr = Marshal.AllocCoTaskMem(fontData.Length);
            try
            {
                Marshal.Copy(fontData, 0, fontDataPtr, fontData.Length);
                fontCollectionFromMemory.AddMemoryFont(fontDataPtr, fontData.Length);
                Thread.Sleep(100);
            }
            finally
            {
                Marshal.FreeCoTaskMem(fontDataPtr);
            }
        }

        // fontCollectionFromFile.AddFontFile(file);
    }
    Console.WriteLine($"PrivateFontCollection's size(filled via AddMemoryFont): {fontCollectionFromMemory.Families.Length}");
    Console.WriteLine($"PrivateFontCollection's size(filled via AddFontFile): {fontCollectionFromFile.Families.Length}");

After running the code above I get the following output:

PrivateFontCollection's size(filled via AddMemoryFont): 34
PrivateFontCollection's size(filled via AddFontFile): 0

This outcome is very confusing...

If I uncomment the following line:

fontCollectionFromFile.AddFontFile(file);

then I get:

PrivateFontCollection's size(filled via AddMemoryFont): 166
PrivateFontCollection's size(filled via AddFontFile): 198

This result is also confusing.

How these outcomes can be explained? What is a proper way to use PrivateFontCollection.AddMemoryFont?

Environment:

  • Windows 10 Home

  • .Net Core 2.2.106

  • System.Drawing.Common 4.7.0

Community
  • 1
  • 1
Alexei
  • 75
  • 2
  • 8
  • 1
    The top Google hit has a very nasty bug, replicated in this code. Marshal.FreeCoTaskMem() must not be called until the font can no longer be used. Practically that means it shouldn't be called until the program calls PrivateFontCollection.Dispose(). Since nobody ever does that, practically that means you should never call FreeCoTaskMem(). – Hans Passant Feb 17 '20 at 16:20
  • Thanks! I will take it into account. Tested my sample with commented Marshal.FreeCoTaskMem(). Outcomes are the same. – Alexei Feb 17 '20 at 17:42

0 Answers0