0

私はこのコードを使用して埋め込みフォントを取得しています:

/// <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;            
    }

このメソッドが短時間に複数回呼び出されると、エラーが発生するように見えるため、スレッドを使用してスレッドが終了するのを待機しようとしています。

このエラーの発生をどのように防ぐことができますか。これは、メソッドが互いにすばやく連続して呼び出されることに関係していると思います。

ここで例外が発生します:

_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;
            }

行g.MeasureString(_text、_font);

ただし、フォントがGetEmbeddedFontメソッドを使用して設定されている場合にのみエラーがスローされるため、エラーがGetEmbeddedFontメソッドにあることはわかっています。

1回は正常に動作しますが、2回目に使用して、最初の直後に使用すると、エラーがスローされます。

そして、コードをデバッグすると、_fontはこれを返します。

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

1 に答える 1

5

AddMemoryFont()にはドキュメントの問題があり、ポインタが有効である必要がある期間が指定されていません。私は常に保守的なルートを選択し、プログラムがプライベートフォントの使用を停止するまでメモリを解放しないようにしまし。これはうまく機能しており、アクセス違反はありません。

したがって、Marshal.FreeCoTaskMem()呼び出しを削除することを強くお勧めします。完全に、Windowsはプログラムが終了したときに自動的にクリーンアップするか、たとえばFormClosedイベントに移動します。m_pfc.Dispose()呼び出しについても同じことが言えます。使い終わるまでリソースを解放しないでください。

于 2012-06-24T19:00:46.180 に答える