Using a method to get an embedded font causes a protected memory error

I use this code to get the embedded font:

/// <summary> /// Returns an Embedded Font /// </summary> /// <param name="ImagePath">String begins with namespace eg 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 Thread to try to wait for it to complete, because an error occurs if this method is called several times in a short amount of time.

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

I get an 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 line g.MeasureString (_text, _font);

However, I know that the error is in the GetEmbeddedFont method, since it only throws an error if the font is specified using the GetEmbeddedFont method.

It will work fine once, but if it is used a second time shortly after the first, it will throw an 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} 
0
source share
1 answer

There is a problem with the documentation with AddMemoryFont (), it does not indicate how long the pointer should remain valid. I always chose a conservative route and did not release memory until the program stopped using the private font. This worked well, no access violations.

Therefore, I highly recommend that you remove the Marshal.FreeCoTaskMem () call. Either completely, Windows automatically clears when the program exits, or moves it, say, to the FormClosed event. The same can be said about calling m_pfc.Dispose (). Do not free resources until you are done with them.

+5
source

All Articles