2

我正在使用 PrivateFontCollection 在我的网络服务器上安装上传的字体。下面的代码有效,但在第二次上传字体时,PrivateFontCollection 引用了上传的第一个字体。所以有些东西没有被正确处理。有人发现我做错了什么吗?

 var fontName = string.Empty;
    using (var ms = new MemoryStream(fontBytes))
    {
        // used to store our font and make it available in our app
        using (var pfc = new PrivateFontCollection())
        {
            //create memory pointer
            IntPtr data = Marshal.AllocCoTaskMem((int)ms.Length);

            try
            {
                //copy the bytes to the unsafe memory block
                Marshal.Copy(fontBytes, 0, data, (int)ms.Length);

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

                //pass the font to the font collection
                pfc.AddMemoryFont(data, (int)ms.Length);
                var fontWithMime = "data:application/x-font-truetype;charset=utf-8;base64," + cleanFontData;

                fontName = pfc.Families[0].Name;

                //db work here
            }
            finally
            {
                ms.Close();
                Marshal.FreeCoTaskMem(data);
            }
        }
    }
4

2 回答 2

2

PrivateFontCollection 是一个非常有缺陷的类,你必须非常小心地使用它。现有代码中的一个非常严重的错误是 Marshal.FreeCoTaskMem() 调用。您可以确保您的代码停止使用您从该系列创建的任何Font 对象之前调用此函数。不这样做会导致随机字形损坏,如果幸运的话,您只会收到 AccessViolationException。根本问题是字体将继续使用您通过 AllocCoTaskMem() 分配的内存,它完全不知道内存不再有效。重新使用内存时会发生损坏。

此外,虽然该类具有 AddMemoryFont() 方法,但它没有相应的 RemoveMemoryFont() 方法。清理的唯一方法是调用 PrivateFontCollection.Dispose()。这将删除集合中的所有字体。与上一段相同的规定,只有在确定不再使用任何 Font 对象时,才能调用 Dispose()。过早调用它不会导致异常。

非常尴尬的行为,使用 PFC 的唯一真正安全的方法是在应用程序的整个生命周期内一直保留它。当然,在 Web 应用程序中非常痛苦。

您可以假设添加的字体是FontFamily[] 数组中的最后一个字体。不是您现在实施的第一个。

于 2016-01-05T21:16:29.043 回答
1

根据AddFontMemResourceEx 函数

要删除已安装的字体,请调用 RemoveFontMemResourceEx。但是,当进程消失时,即使进程没有调用 RemoveFontMemResource,系统也会卸载字体。

但是,我不认为你这样做。这可能是原因。

于 2016-01-05T20:57:16.810 回答