2014-10-29 16 views
6

Ich habe eine Funktion, die eine Privatezurückgibt:.NET Private - wie Dateisperren freizugeben, wenn Sie fertig

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 

ich dann die Funktion wie folgt verwenden:

Using customFonts = Common.GetCustomFonts() 
    ' Do some stuff here 
End Using 

Ich würde erwarten, dass die Dateien werden zwar veröffentlicht, sind aber weiterhin gesperrt: Ich erhalte den folgenden Fehler: 'Die Aktion kann nicht abgeschlossen werden, da die Datei im System geöffnet ist. Schließen Sie die Datei und versuchen Sie es erneut.

Das Herunterfahren der Website in IIS hilft nicht; Wir müssen den App-Pool recyceln, damit er veröffentlicht werden kann.

Kann jemand empfehlen, PrivateFontCollection so zu verwenden, dass die Dateien zwischen den Anwendungen freigegeben werden?

+0

Meine einzige Idee bisher ist, die Schriftart in den Speicher zu laden und stattdessen AddMemoryFont zu verwenden. Auf diese Weise kann ich garantieren, dass PrivateFontCollection niemals die Dateien berührt. – extremeandy

+0

Für eine mögliche Antwort siehe http://StackOverflow.com/Questions/26671026/How-To-Delete-the-file-of-a-privatefontcollection-addfontfile – Horcrux7

+0

Hinzugefügt Connect Bug https://connect.microsoft.com/ VisualStudio/Feedback/Details/1379843 – Peter

Antwort

1

Als Workaround habe ich die Schriftarten in den Speicher geladen und stattdessen "AddMemoryFont" verwendet. Siehe Code unten. Denken Sie daran, dass dies das erste Mal ist, dass ich nicht verwaltete Ressourcen in .NET berührte. Daher kann ich nicht garantieren, dass die unten beschriebene Speicherverwaltung in Ordnung ist.

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