Using a method to get Embedded Font Causes Protected Memory Error

十年热恋 提交于 2019-12-25 07:44:51

问题


I am using this code to get an embedded font:

/// <summary>
    /// Returns an Embedded Font
    /// </summary>
    /// <param name="ImagePath">String begins with namespace e.g MyProgram.Image.png</param>
    /// <returns></returns>
    public static Font GetEmbeddedFont(string FontPath, float Size)
    {
        Font _font = null;
        Thread getFontThread = new Thread(() => GetFont(FontPath, Size, out _font));
        getFontThread.Start();
        getFontThread.Join();
        return _font;            
    }
    #region GetFont
    private static void GetFont(string FontPath, float Size, out Font FontOut)
    {
        Font fnt = null;
        Assembly asm = Assembly.GetExecutingAssembly();
        Stream resStream = asm.GetManifestResourceStream(FontPath);
        if (null != resStream)
        {
            // 
            // GDI+ wants a pointer to memory, GDI wants the memory.
            // We will make them both happy.
            //
            // First read the font into a buffer
            byte[] rgbyt = new Byte[resStream.Length];
            resStream.Read(rgbyt, 0, rgbyt.Length);
            resStream.Close();
            // Then do the unmanaged font (Windows 2000 and later)
            // The reason this works is that GDI+ will create a font object for
            // controls like the RichTextBox and this call will make sure that GDI
            // recognizes the font name, later.
            uint cFonts;
            AddFontMemResourceEx(rgbyt, rgbyt.Length, IntPtr.Zero, out cFonts);
            // Now do the managed font
            IntPtr pbyt = Marshal.AllocCoTaskMem(rgbyt.Length);
            if (null != pbyt)
            {
                Marshal.Copy(rgbyt, 0, pbyt, rgbyt.Length);
                m_pfc = new PrivateFontCollection();
                m_pfc.AddMemoryFont(pbyt, rgbyt.Length);
                Marshal.FreeCoTaskMem(pbyt);
            }
        }

        if (m_pfc.Families.Length > 0)
        {
            // Handy how one of the Font constructors takes a
            // FontFamily object, huh? :-)
            fnt = new Font(m_pfc.Families[0], Size);
        }
        m_pfc.Dispose();    
        FontOut = fnt;            
    }

I use a Thread to attempt to wait for it to finish, because the error seems to occur, if this method is called multiple times within a short space of time.

How can I stop this error occuring, I think it has something to do with the method being called within quick succession of each other.

I get the exception here:

_font = value;
            using (Graphics g = _parent.CreateGraphics())
            {
                SizeF soize = g.MeasureString(_text, _font);
                _size = new Size((int)soize.Width, (int)soize.Height);
                _width = _size.Width;
                _height = _size.Height;
            }

On the line g.MeasureString(_text, _font);

However I know that the error is in the GetEmbeddedFont Method, as it only throws an error if the font is set using the GetEmbeddedFont method.

It will work fine once, but if it is used a second time to shortly after the first, it will throw the error.

And if I debug the code, _font returns this:

{Name = '((System.Drawing.Font)(_font)).fontFamily.Name' threw an exception of type 'System.ArgumentException' Size=15.0}

回答1:


There's a documentation problem with AddMemoryFont(), it doesn't specify how long the pointer needs to remain valid. I've always chosen the conservative route and made sure to not release the memory until after the program stops using the private font. That has worked well, no access violations.

I thus strongly recommend you remove the Marshal.FreeCoTaskMem() call. Either entirely, Windows automatically cleans up when the program terminates, or move it to, say, the FormClosed event. The same goes for your m_pfc.Dispose() call. Don't release resources until you're done with them.



来源:https://stackoverflow.com/questions/11173457/using-a-method-to-get-embedded-font-causes-protected-memory-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!