我有一个返回PrivateFontCollection的函数:
Public Shared Function GetCustomFonts() As PrivateFontCollection
Dim result = New PrivateFontCollection
Dim customFontFiles = {"Garamond.TTF", "Garamond-Bold.TTF", "Garamond-Italic.TTF", "EurostileExtended-Roman-DTC.TTF"}
For Each fontFile In customFontFiles
result.AddFontFile(Hosting.HostingEnvironment.MapPath("/Includes/" & fontFile))
Next
Return result
End Function
然后我使用如下函数:
Using customFonts = Common.GetCustomFonts()
' Do some stuff here
End Using
我希望文件会被释放,但它们仍然被锁定:我收到以下错误:'由于文件在System中打开,因此无法完成操作。关闭文件,然后重试。'
在IIS中关闭网站没有帮助;我们必须回收应用程序池才能发布它。
任何人都可以建议如何使用PrivateFontCollection,以便在使用之间释放文件吗?
答案 0 :(得分:1)
作为一种解决方法,我将字体加载到内存中并使用“AddMemoryFont”代替。见下面的代码。请记住这是我第一次触及.NET中的非托管资源,所以我不能保证下面的内存管理没问题。
Imports System.Drawing.Text
Imports System.Runtime.InteropServices
Public Class CustomFontService
Implements IDisposable
Dim _fontBuffers As List(Of IntPtr)
Dim _collection As PrivateFontCollection
Public Sub New()
_collection = New PrivateFontCollection
_fontBuffers = New List(Of IntPtr)
Dim customFontFiles = {"Garamond.TTF", "Garamond-Bold.TTF", "Garamond-Italic.TTF", "EurostileExtended-Roman-DTC.TTF"}
For Each fontFile In customFontFiles
Dim fontBytes = System.IO.File.ReadAllBytes(Hosting.HostingEnvironment.MapPath("/Includes/" & fontFile))
Dim fontBuffer As IntPtr = Marshal.AllocHGlobal(fontBytes.Length)
Marshal.Copy(fontBytes, 0, fontBuffer, fontBytes.Length)
_fontBuffers.Add(fontBuffer)
_collection.AddMemoryFont(fontBuffer, fontBytes.Length)
Next
End Sub
Public Function GetCustomFonts() As PrivateFontCollection
Return _collection
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
For Each buf In _fontBuffers
If (buf <> IntPtr.Zero) Then
Marshal.FreeHGlobal(buf)
End If
Next
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
Protected Overrides Sub Finalize()
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(False)
MyBase.Finalize()
End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class