【问题标题】:How to dispose of a PrivateFontCollection correctly?如何正确处理 PrivateFontCollection?
【发布时间】:2016-04-09 19:29:57
【问题描述】:

我正在使用 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);
            }
        }
    }

【问题讨论】:

  • 为什么是内存流?你似乎根本没有使用它。尝试以下技巧:将字体保存到临时文件并使用“PrivateFontCollection.AddFontFile”查看错误是否消失。

标签: c# interop unmanaged unmanaged-memory


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    根据AddFontMemResourceEx function

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多