Hallo PDFCreator-Freunde,
ich nutze die COMWrapper.dll für mein VB.net-Projekt. Alles läuft wunderbar. Nur wenn ich ein weiteres mal eine PDF-Datei konvertieren möchte, erhalte ich die Fehlermeldung, dass nur eine Instanz erlaubt sei. In dem Forum gesucht und gefunden: Nutze nun IsInstanceRunning(), wenn die diese True zurückgibt Kill ich die Prozesse die "PDFCreator" lauten.
Ich finde das keine schöne Lösung. Wäre es möglich, die bereits gestartete Instanz zu übernehmen?
Bei dem Kill-Vorgang habe ich außerdem das Problem, dass er teilweise die Queue nicht mehr prüft, obwohl was gedruckt wurde; es kommt ein Timeout-Fehler. Wenn man es anschließend nochmal versucht, funktioniert mein Programmablauf wieder.
Hier mein Code:
[PDFPrinting]
Imports System.Runtime.InteropServices
Imports pdfforge.PDFCreator.UI.ComWrapper
Namespace PDF
''' <summary>
''' Enthält Methoden, um eine PDF Datei zu drucken.
''' </summary>
Public Class PDFPrinting
Implements IDisposable
Private _settings As PDFSettings = Nothing
Private _queue As Queue = Nothing
''' <summary>
''' Gibt zurück, ob min. 1 PDF-Drucker installiert ist, welcher
''' verwendet werden kann.
''' </summary>
''' <returns><c>True</c> wenn min. 1 verwendbarer PDF-Drucker installiert ist; <c>False</c> andernfalls.</returns>
Public ReadOnly Property PDFPrinterInstalled As Boolean
Get
Return IsPDFPrinterInstalled()
End Get
End Property
''' <summary>
''' Gibt die Einstellungen zurück, welche für den Druck gelten sollen.
''' </summary>
''' <returns></returns>
Public ReadOnly Property PDFEinstellungen As PDFSettings
Get
Return _settings
End Get
End Property
''' <summary>
''' Erstellt eine neue Instanz, um PDF-Dateien zu drucken.
''' </summary>
Public Sub New()
Me.Init()
End Sub
''' <summary>
''' Wartet auf einen Druckauftrag in der Warteschlange und
''' wandelt den ersten Druckauftrag, welche auftritt in eine PDF-Datei um.
''' </summary>
''' <param name="FullPath">Vollständiger Pfad inkl. Dateiname, wo die Datei gespeichert werden soll.</param>
''' <exception cref="PDFException">Wenn ein Fehler auftritt beim Umwandeln.</exception>
''' <exception cref="TimeoutException">Wenn nach 15 Sekunden kein Druckauftrag in der Warteschlange eingegangen ist.</exception>
''' <remarks>
''' Befindet sich nicht innerhalb 15 Sekunden der Druckauftrag in der Warteschlange, wird der
''' Vorgang abgebrochen und eine Exception geworfen.
''' </remarks>
Public Sub ConvertToPDF(ByVal FullPath As String)
'Variablendeklaration
Dim job As PrintJob = Nothing
Try
'Auf Druckjob in der Warteschlange warten
If _queue.WaitForJob(15) = False Then
Throw New TimeoutException("Es konnte kein Druckauftrag in der Warteschlange festgestellt werden. Vorgang abgebrochen.")
Else
'Druckauftrag wurde in der Warteschlange empfangen
'Diesen übernehmen wir nun
job = _queue.NextJob
'Einstellungen übernehmen
job.SetProfileByGuid("DefaultGuid")
For Each s As KeyValuePair(Of String, String) In _settings.GetSettings()
job.SetProfileSetting(s.Key, s.Value)
Next
'Umwandeln starten
job.ConvertTo(FullPath)
'Umwandeln erfolgreich beendet?
If (Not job.IsFinished Or Not job.IsSuccessful) Then
Throw New PDFException("Der Druckjob konnte nicht in eine PDF-Datei umgewandelt werden. Der Auftrag war fehlerhaft oder nicht abgeschlossen.")
End If
End If
Catch ex As Exception
'PDF-Exception als Wrapper werfen.
Throw New PDFException("Fehler beim Umwandeln in eine PDF-Datei. " & ex.Message, ex)
Finally
'Variablen wieder freigeben, weil COM-Objekt
job = Nothing
End Try
End Sub
''' <summary>
''' Fügt einen Druckauftrag einer bestehenden PDF-Datei hinzu.
''' </summary>
''' <param name="PDFFile">Bestehende PDF-Datei, an welche eine weitere Seite hinzugefügt werden soll.</param>
''' <exception cref="PDFException">Wenn beim Hinzufügen der Seite ein Fehler auftritt.</exception>
''' <exception cref="TimeoutException">Wenn nach 15 Sekunden der Druckauftrag nicht im Spooler ist.</exception>
Public Sub AddToExistsPDF(ByVal PDFFile As String)
Me.AddToExistsPDF(PDFFile, 1)
End Sub
''' <summary>
''' Fügt mehrere Druckaufträge zu einer bestehenden PDF-Datei hinzu.
''' </summary>
''' <param name="PDFFile">Bestehende PDF-Datei, an welche weitere Seiten hinzugefügt werden soll.</param>
''' <param name="CountJobs">Anzahl der Druckaufträge, auf welche gewartet werden soll.</param>
''' <exception cref="PDFException">Wenn beim Hinzufügen der Seiten ein Fehler auftritt.</exception>
''' <exception cref="TimeoutException">Wenn nach 15 Sekunden nicht die Anzahl an Druckaufträgen eingegangen ist.</exception>
Public Sub AddToExistsPDF(ByVal PDFFile As String, ByVal CountJobs As Integer)
End Sub
''' <summary>
''' Wartet auf eine gewisse Anzahl Druckaufträge in der Warteschlange und
''' wandelt alle Druckaufträge um in eine PDF-Datei.
''' </summary>
''' <param name="FullPath">Vollständiger Pfad, inkl. Dateiname, wo die Datei gespeichert werden soll.</param>
''' <param name="CountJobs">Anzahl der Druckaufträge, auf welche gewartet werden soll.</param>
''' <exception cref="PDFException">Wenn ein Fehler auftritt beim Umwandeln.</exception>
''' <exception cref="TimeoutException">Wenn nach 15 Sekunden nicht die Anzahl an Druckaufträgen eingegangen ist.</exception>
''' <remarks>
''' Befinden sich nicht innerhalb 15 Sekunden alle Druckaufträge in der Warteschlange, wird
''' der Vorgang abgebrochen und eine Exception geworfen.
''' </remarks>
Public Sub MergeToPDF(ByVal FullPath As String, ByVal CountJobs As Integer)
'Variablendeklaration
Dim job As PrintJob = Nothing
Try
'Auf Druckjob in der Warteschlange warten
If _queue.WaitForJobs(CountJobs, 15) = False Then
Throw New TimeoutException("Es wurden nicht alle nötigen Druckaufträge in der Warteschlange festgestellt. Vorgang abgebrochen.")
Else
'Druckauftrag wurde in der Warteschlange empfangen
'Diesen übernehmen wir nun
_queue.MergeAllJobs()
job = _queue.NextJob
'Einstellungen übernehmen
job.SetProfileByGuid("DefaultGuid")
For Each s As KeyValuePair(Of String, String) In _settings.GetSettings()
job.SetProfileSetting(s.Key, s.Value)
Next
'Umwandeln starten
job.ConvertTo(FullPath)
'Umwandeln erfolgreich beendet?
If (Not job.IsFinished Or Not job.IsSuccessful) Then
Throw New PDFException("Der Druckjob konnte nicht in eine PDF-Datei umgewandelt werden. Der Auftrag war fehlerhaft oder nicht abgeschlossen.")
End If
End If
Catch ex As Exception
'PDF-Exception als Wrapper werfen.
Throw New PDFException("Fehler beim Umwandeln in eine PDF-Datei.", ex)
Finally
'Variablen wieder freigeben, weil COM-Objekt
job = Nothing
End Try
End Sub
''' <summary>
''' Initialisiert das PDF-Drucken.
''' </summary>
Private Sub Init()
'Variablendeklaration
Dim queueType As Type = Nothing
Try
'Default-Einstellungen
_settings = New PDFSettings()
'Wenn bereits eine Instanz läuft, killen wir den Prozess
'Denn eigentlich sollte vom PDF-Creator gar nichts laufen.
If Me.IsInstanceRunning() = True Then
For Each proc As Process In Process.GetProcessesByName("PDFCreator")
proc.Kill()
Next
'Drei Sekunden warten, bis wirklich alle Dienste beendet sind
Threading.Thread.Sleep(3000)
End If
'Queue initialisieren
_queue = New Queue()
_queue.Initialize()
Catch ex As Exception
Throw New PDFException("Fehler beim Initialisieren des PDF-Druckers. " &
"PDF-Creator ist nicht installiert oder die COM-Schnittstelle registriert. " &
"Bitte installieren Sie die Anwendung erneut. Fehlermeldung: " &
ex.Message, ex)
End Try
End Sub
''' <summary>
''' Gibt zurück, ob bereits eine Instanz von PDFCreator läuft.
''' </summary>
''' <returns><c>True</c>, wenn bereits eine Instanz läuft; <c>False</c> andernfalls.</returns>
Private Function IsInstanceRunning() As Boolean
'Variablendeklaration
Dim pdfobj As PdfCreatorObj = Nothing
Try
pdfobj = New PdfCreatorObj()
Return pdfobj.IsInstanceRunning
Catch ex As Exception
Throw New PDFException("Fehler beim prüfen, ob PDFCreater-Instanz bereits läuft. " & ex.Message)
Finally
'PDF-Objekt freigeben
pdfobj = Nothing
End Try
End Function
''' <summary>
''' Gibt den Drucker-Namen zurück, welcher für diesen PDF-Druck
''' geeignet ist.
''' </summary>
''' <returns>Namen des installierten und verwendbaren PDF-Druckers</returns>
''' <exception cref="PDFException">Wenn ein Fehler beim Ermitteln des Druckers auftritt oder kein Drucker installiert ist.</exception>
Public Shared Function GetPDFPrinter() As String
'Variablendeklaration
Dim PDFCreator As PdfCreatorObj = Nothing
'Wurde ein Drucker installiert?
If IsPDFPrinterInstalled() = False Then
Throw New PDFException("Es ist kein PDF-Drucker installiert. Bitte installieren Sie die Anwendung erneut.")
End If
Try
'Instanz von PDF-Creator erzeugen
PDFCreator = New PdfCreatorObj()
'Wir nehmen den ersten immer zu findenden Drucker!
'Aufgrunddessen, weil wir bereits geprüft haben, ob überhaupt ein
'Drucker installiert ist, können wir hier gleich auf den Index losgehen.
Return PDFCreator.GetPDFCreatorPrinters.GetPrinterByIndex(0)
Catch ex As Exception
'PDF-Exception als Wrapper werfen.
Throw New PDFException("Der PDF-Drucker konnte nicht ermittelt werden.", ex)
Finally
'PDF-Creator Instanz freigeben.
PDFCreator = Nothing
End Try
End Function
''' <summary>
''' Prüft, ob PDF-Creator installiert ist und ob min. 1
''' PDF-Drucker verfügbar ist.
''' </summary>
''' <returns><c>True</c> wenn PDF-Creator installiert ist und min. 1 Drucker verfügbar ist; <c>False</c> andernfalls.</returns>
Private Shared Function IsPDFPrinterInstalled() As Boolean
'Variablendeklaration
Dim PDFCreator As PdfCreatorObj = Nothing
Try
PDFCreator = New PdfCreatorObj()
If PDFCreator.GetPDFCreatorPrinters.Count > 0 Then
Return True
End If
Return False
Catch ex As Exception
Console.WriteLine("Ausnahme bei PDF-Drucker installiert: {0}", ex.Message)
Return False
Finally
PDFCreator = Nothing
End Try
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' Dient zur Erkennung redundanter Aufrufe.
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
If _queue IsNot Nothing Then
_queue.ReleaseCom()
End If
'Prüfen ob der Prozess noch läuft und dann abwürgen
For Each proc As Process In Process.GetProcessesByName("PDFCreator")
proc.Kill()
Next
End If
_queue = Nothing
_settings = Nothing
End If
disposedValue = True
End Sub
' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
Public Sub Dispose() Implements IDisposable.Dispose
' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in Dispose(disposing As Boolean) weiter oben ein.
Dispose(True)
End Sub
#End Region
End Class
End Namespace
[Aufruf]
'Ist die Datei bereits eine PDF?
If IO.Path.GetExtension(org_dateiname).ToLower().Equals(".pdf") = True Then
'Es handel sich bereits um eine PDF-Datei.
'Die schreiben wir einfach da hin, wo der Anwender sie hinhaben will.
Utilities.FileSystem.Dateien.WriteStreamToFile(dbAkten.GetDokument(aktendatei_id), filename, True)
Else
'Datei im TempPfad speichern
Utilities.FileSystem.Dateien.WriteStreamToFile(dbAkten.GetDokument(aktendatei_id), tempFile, True)
'Es ist keine PDF! Wir müssen die Datei mit dem Standard-Programm
'öffnen und dann versuchen zu drucken
proc = New Process() With {
.StartInfo = New ProcessStartInfo(tempFile) With {
.Verb = "printto",
.WindowStyle = ProcessWindowStyle.Hidden,
.Arguments = Utilities.PDF.PDFPrinting.GetPDFPrinter()
}
}
proc.Start()
proc.WaitForExit(60000)
'PDF-Datei erzeugen
Using pdf As New Utilities.PDF.PDFPrinting()
pdf.ConvertToPDF(filename)
End Using
End If