Statistik Plugin für Wordpress Erweiterte Rechteverwaltung für Joomla mit JACLPlus

PDFs in C# unter Windows ausdrucken

Um pdf-Dokumente unter Windows aus einer .NET-Anwendung heraus auszudrucken, gibt es die verschiedensten Möglichkeiten. Es gibt zunächst einmal eine Vielzahl freier oder kostenpflichtiger Bibliotheken, mit denen mehr oder weniger komfortabel pdf-Dokumente aus .NET heraus erstellt werden können. Geht es allerdings darum, ein Dokument auszudrucken, genügen freie Angebote offenbar nicht mehr und man müsste auf eine kostenpflichtige Komponente zurückgreifen. Will man lediglich ein vorhandenes Dokument ausdrucken, schiesst man damit vermutlich mit Kanonen auf Spatzen. Ein einfacher Weg ist hier, eine vorhandene Installation von Acrobat oder dem Reader einzusetzen. Beide sind in der Lage, Dokumente auszudrucken und warum sollte man davon nicht Gebrauch machen? (Vorausetzung ist hier wie gesagt, dass eine der beiden Anwendungen auf Zielrechner vorhanden ist.)

Nun bieten der Acrobat, wie auch der Reader einem Entwickler durchaus die Möglichkeit, gegen ihre Dlls zu linken und so auf dem “offiziellen” Weg auf ihre Dienste zurückzugreifen. Da ist zunächst einmal nichts geheimnisvolles dabei. Adobe bietet zudem eine relativ umfangreiche Dokumentation der Objektmodelle des Acrobats (die sogar ein kleines Kapitel über die Anbindung an .NET beinhaltet). Der Haken hierbei ist jedoch, dass sich die Objektmodelle beider Anwendungen (und vermutlich sogar einzelner Versionen) voneinander unterscheiden. So muss bei der Erstellung der eigenen Anwendung berücksichtigt werden, welche Acrobat (Reader)-Version später auf dem Zielrechner vorgefunden wird. Jeder normale Mensch würde jetzt vermutlich erstmal an eine späte Bindung denke, um diese Unterscheidung zur Laufzeit vornehmen zu können. Das Problem hierbei ist allerdings, dass die Namen von Klassen und Methoden der installierten Acrobat-Version dann spätestens zur Laufzeit bekannt sein müssen. Sicher kriegt man das irgendwie hin – es geht aber auch einfacher.

Es gibt nämlich ausser unserer Anwendung auf dem Zielrechner noch jemanden, der das gleiche Problem hat: die Shell, resp. der Explorer. Über das Kontextmenü kann ein Dokument ausgewählt und ein Druckauftrag angestossen werden. Die Shell muss also auch wissen, welche Anwendung sich für einen bestimmten Dateityp verantwortlich fühlt, ohne einzelne Versionen berücksichtigen zu müssen. Zu diesem Zweck sind in Windows (genau genommen in der Registry) bekanntlich Dateitypen mit Anwendungen verknüpft. In .NET kann man nun genau diese Verknüpfung ausnutzen. Dazu erstellt man eine Instanz von Process aus dem Namespace System.Diagnostics. Parametriert wird diese Instanz über eine Property StartInfo. Zu diesen Parametern gehört nicht nur der Dateiname der zu öffnenden Datei, sondern auch ein sogenanntes Verb. Verbs sind die Befehle, welche die Shell an eine Anwendung beim Start (per COM, DDE oder als Kommandozeilenparameter) überträgt. Die Anwendung auf der Gegenseite sollte natürlich im Stande sein, dieses Verb zu verstehen. Windows ist hier lediglich bei der Übetragung involviert. Ein Verb wie print wird allerdings im Allgemeinen bei der Installation einer Anwendung angelegt.

Versucht man nun, aus dem Anwendungscode heraus über die Shell ein pdf Dokument auszudrucken, tritt das Problem auf, dass eine Instanz des Acrobat (Readers) in der Taskleiste erhalten bleibt. Über Process.StartInfo kann ihr das abgewöhnt werden. Der folgende Code ermöglicht es, ein pdf auszudrucken und beendet anschließend den Acrobat Reader.

Process proc = new Process ();
proc.StartInfo.CreateNoWindow = false;
proc.StartInfo.Verb = “print”;
proc.StartInfo.FileName = “C:\\test.pdf”;
proc.Start();
proc.WaitForExit(10000);
proc.CloseMainWindow();
proc.Close();

Sollen mehrere Dokumente hintereinander gedruckt werden, ist hier eine kleine Optimierung möglich: Verzichtet man auf die Beendigung des Prozesses, bleibt die Instanz des Acrobat auch nach dem Druckauftrag noch (minimiert) erhalten. Bei weiteren Druckaufträgen wird dann keine neue Instanz gebildet, sondern das Verb an diese übertragen. Man spart dadurch die Zeit für den Programmstart des Acrobat.

Tags:, , ,

Bookmarken bei... del.icio.us:PDFs in C# unter Windows ausdrucken furl:PDFs in C# unter Windows ausdrucken Y!:PDFs in C# unter Windows ausdrucken

8 Kommentare to “PDFs in C# unter Windows ausdrucken”

  1. Magier schreibt:

    Hallo.

    Zitat:
    “Nun bieten der Acrobat, wie auch der Reader einem Entwickler durchaus die Möglichkeit, gegen ihre Dlls zu linken und so auf dem “offiziellen” Weg auf ihre Dienste zurückzugreifen.”

    Kann mir jemand sagen wie das denn geht? Ich habe bisher mit Acrobat 6 gedruckt, per /t command. Nun möchte ich den 8 benutzen, bei dem dies nicht mehr funktioniert. Ich weiß also dass ich immer mit 8 meine PDF drucken möchte. Wie linke ich die Funktionen des 8 denn in mein Projekt ein um einen internen druckbefehl an den Reader abzusetzen?

    Danke & Gruß

  2. Magier schreibt:

    Was ich noch vergessen habe: Eine meiner Anforderungen ist, dass ich auf einem bestimmten Drucker drucken muss, ohne den Standarddrucker umzuhängen. Dies bietet die print-with-verb Methode leider nicht, kann man dies über die DLL Einbindung erreichen?

    Gruß

  3. szimmer schreibt:

    Um aus einer .NET-Anwendung heraus ein Pdf-Dokument zu drucken, brauchen wir erstmal eine passende Dll. Um von Visual Studio aus gegen die Dll zu linken, fügt man dem aktuellen Projekt einen Verweis hinzu und gibt als Verweisziel die COM-Komponente der lokal installierten Acrobat-Type-Library an.
    Dann kann man bspw. mit dem folgenden Codesegment
    AcroPDFLib.AcroPDF pdf = new AcroPDFLib.AcroPDFClass ();
    pdf.LoadFile (p_strFileName);
    pdf.Print ()
    eine Datei drucken.

    Eine andere Möglichkeit ist, über die Programm-ID einen in der Registry registrierten Typ zu instantiieren. Das kann dann so aussehen (Reader):
    Type tpAcrobat = Type.GetTypeFromProgID (”AcroPDF.PDF”);
    oder so (Acrobat)
    Type tpAcroApp = Type.GetTypeFromProgID (”AcroExch.App”);
    Type tpAcroPDDoc = Type.GetTypeFromProgID (”AcroExch.PDDoc”);
    Type tpAcroAVDoc = Type.GetTypeFromProgID (”AcroExch.AVDoc”);
    Hat man ein Typ-Objekt, kann man mit dem Activator eine Instanz bilden und mit dieser den Druckvorgang anstoßen.

    Der Vorteil ist hier, dass man zur Übersetzungszeit die Dll nicht kennen muss. Allerdings verlässt man sich im Gegenzug darauf, dass auf dem Rechner, auf dem die Applikation später läuft, eine passende Version vom Acrobat (resp. Reader) installiert ist.

    Was die Wahl des Druckers angeht, weiss ich im Augenblick leider auch kein Mittel. Über die Methode AcroPDFLib.printWithDialog () kann man
    einen Druckdialog einblenden und den Drucker manuell auswählen. Ich vermute aber mal, dass das nicht ausreicht.

    Gruß

  4. Jan schreibt:

    coole Sache. Wie kann ich denn jetzt noch den Drucker auswählen?

    Grüße
    Jan

  5. Felix schreibt:

    Habe die gleiche Frage wie Jan. Hat da jemand eine Idee?
    Kann ich in C# irgendwie “kontrollieren”, ob alles geklappt hat? Jetzt mal abgesehen von try, catch…

    Gruß Felix und vielen Dank für den Tipp!

  6. Christian schreibt:

    Open Source Projekt

    PdfSharp

    http://www.pdfsharp.net/Features.ashx

    Dort sind allle Funktionen implementiert.

  7. Quinte schreibt:

    “.. Dort sind alle funktionen implementiert.”

    Na Klasse, aber nur eine brauchbare Druckfunktion fehlt da leider auch.

    Irgendwie scheint es keine vernünftige Lösung zu geben ohne gravierende Einschränkungen aus dem Programm heraus über ein Printerdialog ein bereits existierendes PDF-File zu drucken.

  8. Kai schreibt:

    Der Druck über Acrobat mit “shell” oder ähnlichen “Scherzen” ist total sinnlos. Auf die Methode bekommt man vielleicht mal ein oder zwei Blatt gedruckt aber mehr auch nicht. Das Problem mit dem Standardrucker ist nicht lösbar (meines Wissens) und den Prozess wird man eben nicht ordentlich los… mal abgesehen davon, dass das Fenster des Readers nervt. Wir haben sehr viel probiert – wird nix! Ist irgendwo aber auch einzusehen – schließlich bietet Adobe entsprechende Bibliotheken für sehr(!!) viel Geld an und die soll ja auch jemand kaufen..
    Die m.E. beste Methode findet man hier: http://www.wpcubed.com/ . Die Leistung, die man erwartet (wenngleich noch kleinere Macken vorhanden sind) und ein faires Lizenzmodell.
    Ne Demo kann man runterladen und mal probieren…

Ein Kommentar hinterlassen