Laden...

PDF Dokumente aus C# heraus drucken

Erstellt von gelöschtem Konto vor 14 Jahren Letzter Beitrag vor 13 Jahren 20.210 Views
Gelöschter Account
vor 14 Jahren
PDF Dokumente aus C# heraus drucken

Hallo, gibt es eine Möglichkeit, PDF-Dokumente ohne installierten Adobe-Reader auf einem Standardrucker auszudrucken?

Oder gibt es für den Adobe Reader APIs? Oder muss man das ganze irgendwie über die CMD-Shell anhand eines Prozessaufrufs mittels der Adobe.exe zusammenbasteln?

Wenn möglich möchte ich "nur" mit C# Mitteln und Adobe.exe arbeiten, ohne Opensource-Bibliotheken.

313 Beiträge seit 2006
vor 14 Jahren

Das ganze sollte ganz einfach gehn
Der Batch befehl wuerde wie folgt aussehen:
c:\Program files\AdobeAcrobat 7.0\Reader\acrord32.exe /t c:\test.pdf

Das ganze kannst du dann mit Process.Start(...starten.

Ein beispiel zu System.Process.Start findest du hier.

3.728 Beiträge seit 2005
vor 14 Jahren

Oder gibt es für den Adobe Reader APIs?

Der Reader installiert automatisch ein ActiveX-Steuerelement. Das kannst Du direkt in Deiner Anwendung aufrufen und alle Funktionen wie Drucken etzc. direkt ansprechen. Du musst das Steuerelement als COM-Verweis hinzufügen (heißt glaube ich "Adobe Acrobat Control" oder so ähnlich).

J
1.114 Beiträge seit 2007
vor 14 Jahren

Der Reader installiert automatisch ein ActiveX-Steuerelement.

Wobei aber peinlichst auf die Acrobatversion zu achten ist. Wenn der Zielrechner eine andere Acrobat Version installiert hat wie dein Entwicklungsrechner, schlägts fehl.

Eine Alternative zu Acrobat ist GPrint.exe, die in Ghostscript und Ghostview enthalten ist. Ist, finde ich, wesentlich schlanker als ein Acrobat Reader, und auch schneller beim Drucken. Über verschiedene Commandline Parameter können noch unterschiedliche Druckoptionen definiert werden: Druckername, Anzahl Kopien usw.

313 Beiträge seit 2006
vor 14 Jahren

jop oder eben das acrobat ueber die commandline ansteuern ist sicher auch nicht kritisch mit der versionierung

4.506 Beiträge seit 2004
vor 14 Jahren

Hallo zusammen,

die Quizfrage war doch:

PDF-Dokumente ohne installierten Adobe-Reader auf einem Standardrucker auszudrucken?

Und dazu kann ich nur sagen, wahrscheinlich geht das nicht. Es gibt diverse (auch kostenlose) PDF-Drucker, diese richten sich als Drucker ein und produzieren eine PDF Datei, das ist aber in Deinem Fall nicht gewünscht, weil es ja nicht der Standarddrucker ist und die Datei dann immer noch nicht gedruckt ist.

Jelly hat hier für diesen Fall eine gute Alternative genannt, aber auch die muss installiert werden:

Eine Alternative zu Acrobat ist GPrint.exe, die in Ghostscript und Ghostview enthalten ist. Ist, finde ich, wesentlich schlanker als ein Acrobat Reader, und auch schneller beim Drucken. Über verschiedene Commandline Parameter können noch unterschiedliche Druckoptionen definiert werden: Druckername, Anzahl Kopien usw.

Grüße
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

Gelöschter Account
vor 14 Jahren

Die Software wird vermutlich später kommerziell benutzt, bzw. verkauft. Deshalb kann/möchte ich nicht "irgendwelche" Programme in Anspruch nehmen. Der Adobe Reader wäre die einzige Ausnahme, da der schon praktisch überall installiert ist.

Falls ich es mit einem Batchbefehl geht, wie kann ich das Pfad- und Versionsunabhängig machen? Damit das auch wirklich auf jedem PC läuft (XP, VIsta, Adobeversion 7,8,9..), und das, auch wenn kein User angemeldet ist?

PS: Habe in der Konsole mal den Befehl abgesetzt: ...\Reader\acrord32.exe /t c:\test.pdf , da geht bei mir nur der Reader auf, ohne Printbefehl o.ä. Ich habe die Version 9. Haben die Switchs geändert oder mach ich was falsch?

PS2: Ich google gerade nach Adobe-Apis. Kann ich evtl mit dem Adobe Acrobat SDk 8.0 etwas machen?

3.728 Beiträge seit 2005
vor 14 Jahren
Versionsunabhängig

Du kannst das auch mit dem ActiveX-Control versionsunabhängig machen. Der Schlüssel dazu ist die Klasse AxHost im Namensraum System.Windows.Forms. Damit kann man ganz einfach ohne Interop-Verweise ActiveX-Controls hosten. Du benötigst nur die CLSID, welche bei allen Acrobat-Versionen gleich ist. Nur die 64-Bit Varianten haben eine andere CLSID. Also eine CLSID für 32 Bit und eine für 64 Bit.

Die CLSID kannst Du heruasfinden, indem Du in der Registry nach der ProgId des ActiveX-Controls suchst.

Gelöschter Account
vor 14 Jahren

@Rainbird: Das wäre toll. Ich habe noch nie ActiveX aus C# angesteurt... werds aber versuchen. Beispielcode wäre natürlich toll;)

So, geh mal schlafen. Das ausdrucken von PDFs scheint ja wirklich nicht trivial zu sein...

Gelöschter Account
vor 14 Jahren

Die ProgID habe ich, wie weiter?

3.728 Beiträge seit 2005
vor 14 Jahren
AxHost

Hallo gijoe222,

da sowas schon öfter gefragt worden ist, habe ich ein kleines Beispiel-Projekt unter Adobe Reader ActiveX ohne Interop-Verweis versionsunabhängig in Windows.Forms hosten gepostet.

Das Drucken ist schon trivial. Im einfachsten Fall ist es eine Zeile Code:


/// <summary>
    /// .NET Wrapper für Adobe Reader ActiveX-Steuerelement
    /// </summary>
    public class AdobeReaderControl : AxHost
    {
        /// <summary>
        /// Hostet das Adobe Reader ActiveX-Steuerelement in Windows.Forms.
        /// </summary>
        public AdobeReaderControl()
            : base("{CA8A9780-280D-11CF-A24D-444553540000}") // CLSID des Adobe Readers (ist bei allen 32-Bit Versionen gleich)
        {}

        ...

        /// <summary>
        /// Druckt die geladene PDF-Datei.
        /// </summary>
        public void Print()
        {
            // Print-Methode auf dem Adobe Reader aufrufen
            this.GetOcx().GetType().InvokeMember("Print", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, this.GetOcx(), new object[0] );
        }
    }

Gelöschter Account
vor 14 Jahren

Hey coool! Besten Dank für das Posten dieses Codes!

185 Beiträge seit 2007
vor 14 Jahren

Wenn ich die Prozessvariante mit bestimmten Parametern wähle, stoße ich auf 2 Probleme:

  • Das Konsolenfenster taucht auf, obwohl ich die Anweisung gebe, dass kein Fenster erscheinen soll.

  • Wenn ich nicht auf einem physikalischen Drucker drucke, sondern auf einem PDF-Drucker, dann wird die Codeabarbeitung direkt nach dem Starten des Prozesses weitergeführt. Gibt es eine Möglichkeit, mit der Abarbeitung zu warten? WaitForExit() scheint nicht die ultimative Lösung zu sein.

Wenn ich nach dem Starten des Prozesses File.Move (Umbennen) auf den erstellten File mache, wird eine Exception geworfen, dass auf die Datei nicht zugegriffen werden kann.

Hatte jemand schon einmal ähnliche Probleme und evtl. Lösungen zu diesen beiden Problemen?

3.728 Beiträge seit 2005
vor 14 Jahren
Prozessvariante

Hallo timmi,

für eine weitreichende Automatisierung ist die Prozessvariante nicht die beste Wahl. Du solltest stattdessen das COM-Objektmodell der Adobe Produkte nutzen. Damit hast Du über alles die volle Kontrolle (Sichtbarkeit, Drucken etc. ).

So kannst Du auch eine Anwendungsinstanz des Adobe Readers (bzw. Acrobat Professional) fernsteuern.

Eine Frage noch: Warum willst Du ein PDF auf einem PDF-Drucker ausdrucken? Das ergibt für mich keinen Sinn.

185 Beiträge seit 2007
vor 14 Jahren

Von der COM-Variante wurde doch abgeraten, weil so "peinlichst genau" auf die Version geachtet werden muss oder?

Auf der anderen Seite: Kann man den Verweis nicht lokal mit kopieren und dann sogar ohne eine Adobe-Installation auskommen?

Wieso rätst du nicht (diese Variante hätte ich jetzt eher bevorzugt) zu deiner Lösung mit der CLSID?


Anderes Thema:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Naja, 'tschuldigung: Genauer gesagt drucke ich auf einen Postscript-Drucker. Ein paar mal hintereinander. Und da dieser ja immer in die selbe Datei druckt, muss ich die Dateien nach einem Druckauftrag umbenennen, dies funktioniert aber ohne weiteres nicht, weil er eben ohne Verzögerung direkt zum File.Move springt, wobei die Datei noch "bedruckt" wird.

Ich hab dieses Problem so gelöst:

                                                PrintPS(Dokument[i]);

                                                while (!File.Exists(File))
                                                    Thread.Sleep(2000);
                                                Thread.Sleep(2000);

Ich finde diese Lösung allerdings sehr unbefriedigend, auch wenn Zeit eigentlich eher weniger eine Rolle spielt... es ist einfach alles andere als elegant... 😦

Gibt es eventuell irgendwelche Events (tiefer in Windows drin) die man abfangen und erst beim Auslösen dieses Events mit der Abarbeitung fortfahren könnte?

Ich danke dir übrigens vielmals für deine Antwort! 😃

185 Beiträge seit 2007
vor 14 Jahren

Hat niemand eine Idee zu diesem Problem?

456 Beiträge seit 2007
vor 14 Jahren

Ich möchte mal den Thread wieder öffnen, da ich aktuell das gleiche Problem habe. Ich würde gerne eine laufende Lösung mittels GPrint.exe mit einer API-Variante ersetzen.

Nun ist ja wieder eine Zeit lang vergangen - deshalb wollte ich hier mal nachfragen, ob es mittlerweile nicht andere Lösungen gibt?

Vielen Dank schon einmal im Voraus für eure Antworten

888 Beiträge seit 2007
vor 13 Jahren

Ich mach das aktuell so:


/// <summary>
        /// Druckt ein PDF Dokument 
        /// </summary>
        /// <param name="path">Pfad zum Dokument</param>
        public static void PrintPDFFile(string path)
        {
            FileInfo fileInfo = new FileInfo(path);
            if(!fileInfo.Exists)
            {
                throw new FileNotFoundException();
            }

            int id = 0;

            try
            {
                using(Process proc = new Process())
                {
                    proc.StartInfo.Verb = "print";
                    proc.StartInfo.FileName = path;
                    proc.StartInfo.CreateNoWindow = true;
                    proc.StartInfo.UseShellExecute = true;
                    proc.StartInfo.ErrorDialog = true;
                    proc.Start();

                    id = proc.Id;
                    proc.WaitForExit(10000);
                }
            }
            catch
            {
                //IGNORE 
            }
            finally
            {
                HelperUtils.killProcessById(id);
            }
        }

        /// <summary>
        /// Beendet einen Prozess an Hand seiner Id
        /// </summary>
        /// <param name="id">ProcessId</param>
        private static void killProcessById(int id)
        {
            foreach(Process p in Process.GetProcesses())
            {
                if(p.Id == id)
                {
                    p.Kill();
                    break;
                }
            }
        }

456 Beiträge seit 2007
vor 13 Jahren

@Joetempes,

sollte aber nur dann gehen, wenn Adobe installiert ist, und genau das dauert dann eben ewig, weil im Hintergrund die Standardprozesse verwendet werden.

Ist zwar schon wieder über 1 Jahr her, aber ich denke, ohne Kohle zu investieren, ist gprint die beste Lösung auf der .NET-Schiene und so läuft das auch jetzt produktiv.

Lass' mich aber gerne eines besseren belehren.

M
1 Beiträge seit 2011
vor 13 Jahren
Einfach das Browserplugin nutzen

Das allereinfachste und total unabhängig vom PDF Reader ist es, einfach das Webbrowsercontrol zu benutzen und auf die PDF Datei zu navigieren. Egal welcher PDF Viewer installiert ist, es wird auf das entsprechende Browser Plugin zurückgegriffen und die Datei wird angezeigt. Man muss sich mit keinem Lizenzproblem rumärgern, muss auf keine Versionen achten... es funktioniert einfach

456 Beiträge seit 2007
vor 13 Jahren

@Morloc,

für Massendruckaufträge imo nicht geeignet, da erhebliche Performanceprobleme ... da können die beim Konfektionieren Däumchen drehen 😉 ... von Ansteuerung verschiedener Drucker via Threads ganz zu schweigen und usus ist es auch nicht, aus z.B. einem Service heraus ein (Browser) Controlelement zu instanzieren.