Laden...

Adobe Reader ActiveX ohne Interop-Verweis versionsunabhängig in Windows.Forms hosten

Erstellt von Rainbird vor 14 Jahren Letzter Beitrag vor 4 Jahren 43.153 Views
Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren
Adobe Reader ActiveX ohne Interop-Verweis versionsunabhängig in Windows.Forms hosten

Beschreibung:

Dieses kleine Beispielprojekt zeigt, wie man - mit wenigen Zeilen Code - das ActiveX-Steuerelement des Adobe Readers (früher Acrobat Reader) verwenden kann, ohne einen COM-Verweis ins eigene Projekt einzufügen.

Außerdem funktioniert das mit Verschiedenen Versionen des Adobe Readers! Es spielt keine Rolle, ob man Version 7,8 oder 9 installiert hat.

Dies ist möglich, da die CLSID der verschiedenen Versionen des ActiveX-Steuerelements trotzdem immer die Selbe ist. Mit der abstrakten Basisklasse System.Windows.Forms.AxHost kann man sehr leicht Wrapper für ActiveX-Steuerelemente schreiben. Man muss nur die CLSID kennen (Wenn man nur die ProgId weiss, kann man in der Registry unter HKEY_CLASSES_ROOT danach suchen und kommt so auch an die CLSID).

Das Beispiel umfasst ein C#-Projekt mit einem Windows.Forms-Formular und einem einfachen Adobe Reader-Wrapper, der Anzeigen, Laden und Drucken kann.

Achtung! Das Beispiel funktioniert nur mit der 32-Bit Version des Readers. Die 64-Bit Version hat eine andere CLSID. Da ich leider kein 64-Bit System am laufen habe, konnte ich auch die entsprechende CLSID für die 64-Bit Reader-Version nicht ermitteln. Wenn jemand so freundlich ist, die 64-Bit CLSID zu posten, kann ich das noch mit Fallunterscheidung einbauen.

Schlagwörter: Acrobat, PDF, Adobe Reader, ActiveX, versionsunabhängig, AxHost

F
26 Beiträge seit 2008
vor 14 Jahren

Ist es damit auch möglich das Aussehen zu bestimmen ?
So war es zB. mit dem "Normalen" ActivX möglich:


this.AxAcroPDF1.setLayoutMode("SinglePage");
this.AxAcroPDF1.setPageMode("none");
this.AxAcroPDF1.setShowToolbar(false);

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren
Aussehen

Ja, das geht ohne weiteres. Es ist ja immer noch das Selbe ActiveX-Steuerelement, nur eben über späte Bindung angesprochen. Du musst einfach Wrapper-Methoden hinzufügen (so wie LoadFile und Print). Der Zugriff auf die Original-Methoden erfolgt mittels Reflection.

F
26 Beiträge seit 2008
vor 14 Jahren

hey rainbird,

danke für das tolle snippet!
ich habe einen 64bit pc zu hause, sag mir wie man die clsid herausfindet, dann geb ich die dir.
habe das bisher versucht und schon mehrere unterschiedliche clsids gefunden, aber keine hat funktioniert.

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren
Clsid

Hallo freako32,

Du solltest die CLSID finden, wenn Du in der Registry unter HKEY_CLASSES_ROOT nach "AcroPDF" suchst.

582 Beiträge seit 2008
vor 14 Jahren

Hallo Rainbird,

ich deinen o.g. Code in einem WPF Control verpacken. Also erst ein WPF UserControl mit einem WindowsFormHost und darein dann das AdobeReaderControl.

Doch wenn ich dann this.GetOcx(); ausführen lasse, dann wird kein Object zurück geliefert. Eine Idee warum?

Gruß dat Tala

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren
Wpf

Hallo Taladan,

sorry, hab mit WPF sogut wie keine Erfahrung.

T
2 Beiträge seit 2010
vor 14 Jahren
64bit

Hallo zusammen

Habe den Code unter Windows 7 64bit ausprobiert und habe das Projekt auch mit der "64bit CLSID" aus der Registry nicht zu Laufen gebracht. Der Grund ist vermutlich, dass Acrobat Reader selbst keine 64bit-Version ist, sondern immer unter 32bit zu laufen scheint. Dementsprechend funktioniert mit der von Rainbird angegebenen CSLID alles bestens, wenn man explizit ein 32bit-Projekt (x86) erstellt.

Allerdings ist mir noch nicht klar, was das Erstellen eines eigenen AxHosts mit Reflection denn bringen soll. Der COM-Wrapper von Visual Studio macht ja auch nicht viel anderes, oder? Vielleicht kann Rainbird mir hier auf die Sprünge helfen?

Besten Dank,
Thomas

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren
Verschiedene Reader Versionen

Hallo tommaso,

der von VS erzeugte Wrapper läuft nicht mit verschiedenen Reader-Versionen. Ein für Adobe Reader 9 erstellter Wrapper, verweigert z.B. auf einem Kundenrechner den Dienst, auf dem nur die Version 7 installiert ist. Das ist bei meiner Methode nicht der Fall. Egal welche Reader-Version (ab 6.0 aufwärts sollte es laufen), das AxHost + Reflection Gespann arbeitet immer ordentlich.

T
2 Beiträge seit 2010
vor 14 Jahren

Danke für die Info, Rainbird. Weisst Du, weshalb das so ist? Ich dachte, der COM-Wrapper von Visual Studio referenziert auch nur eine CSLID?

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren
Änderungen

Das ist durch Unterschiede in den Schnittstellen der verschiedenen Versionen bedingt. Wenn z.B. bei einer neuen Version eine Methode plötzlich einen optionalen Parameter mehr hat, ist die Schnittstelle nicht mehr 100% kompatibel.

Mit einem spät gebundenen Aufruf klappt es aber trotzdem, vorausgesetzt man gibt nur die Parameter an, die in der ältesten zu unterstützenden Version vorhanden sind.

Natürlich können auch neue Methoden dazukommen, oder neue Enums usw.

Um genau zu untersuchen, müsste man den von AxImp.exe erzeugten Wrapper-Code analysieren. Durch anhängen von /Source an AxImp generiert das Tool nicht nur die Wrapper-Assembly, sondern spuckt auch den C#-Code dazu aus. Windows Forms ActiveX Control Importer-Tool (Aximp.exe)

Durch Anpassen des Wrapper-Codes kann man vielleicht auch die nötige Kompatibilität herstellen. Das wäre einen Versuch wert.

314 Beiträge seit 2010
vor 14 Jahren

Hallo!

Ich bin neu hier. Deswegen stelle ich mich zunächst vor: Ich programmiere seit vielen Jahren in C/C++ und Team Developer von der Fa. Unify (früher Gupta, dann Centure und heute Unify).

Seit wenigen Wochen bin ich dabei, mich in C# und das .NET-Framework einzuarbeiten. Am Anfang war das nicht gerade leicht für diesen alten C/C++-Programmierer, sich einige Sachen abzugewöhnen und andere zu erlernen. Nun bin ich ziemlich begeistert von den vielen Möglichkeiten der Sprache und des Frameworks und die Informationsgewinnung im Internet ist bärig.

Und genau durch Informationssuche bin ich auf diese Seite gestoßen. Respekt! Eine hervorragende Seite, die mir bereits geholfen hat. Ich wollte selbsterstellte PDF-Dateien in einer eigenen Form darstellen und bin in diesem Thread gelandet. Wunderbar und vielen Dank an Rainbird.

Nun zwei kurze Fragen:

  1. Wo erhalte ich Information über die zur Verfügung stehenden Methoden und 2) ist die Benutzung dieses Controls kostenfrei oder muss man bei Adobe irgendetwas Lizenzieren? Ich war nämlich stundenlang auf der Adobe-Seite und habe mir das SDK angeschaut, irgendwann habe ich aber nicht mehr gewusst, was ich wirklich davon brauche und was das kostet.

Es wäre schön, wenn jemand mir diese Fragen beantworten könnte.

Vielen Dank im voraus!

René

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 14 Jahren

Hallo pollito,

das Control wird automatisch mit dem kostenfreien Adobe Reader installiert. Wenn immer PDF-Dateien innerhalb des Internet Explorers angezeigt werden, kommt dabei dieses ActiveX-Control zum Einsatz. Der Adobe Reader - und damit auch dessen ActiveX-Control - kann gebührenfrei genutzt werden. Details dazu kannst Du dem Lizenzvertrag des Adobe Readers entnehmen.

Kostenpflichtig ist Adobe Acrobat. Mit Acrobat kann man PDFs erstellen. Der Adobe Reader kann nur PDFs anzeigen. Wenn Du PDFs mit C# erstellen willst, gibt es eine kostenfreie Alternative zu Adobe Acrobat: iTextSharp

Du kannst ein neues Visual Studio Projekt erstellen, den COM-Verweis für das ActiveX-Control einfügen und Dir die Methoden ganz normal im Visual Studio Objektbrowser ansehen.

Ansonsten gibt es das Adobe Reader Developer Center: http://www.adobe.com/devnet/reader/

Danke für die Blumen.

314 Beiträge seit 2010
vor 14 Jahren

Hallo Rainbird,

zunächst vielen Dank für deine ausführliche Antwort.

(...) Der Adobe Reader - und damit auch dessen ActiveX-Control - kann gebührenfrei genutzt werden. Details dazu kannst Du dem Lizenzvertrag des Adobe Readers entnehmen.

Danke nochmals. Mit AcroPDF erreiche fast alles, was ich brauche. Allerdings bietet dieses Control keine Möglichkeit, einen "Silent-Print" mit Angabe des Zieldruckers zu machen. Sehr schade.

Wenn Du PDFs mit C# erstellen willst, gibt es eine kostenfreie Alternative zu Adobe Acrobat:
>

Ich erstelle zurzeit die PDFs über einen Umweg. Ich habe eine Anwendung, die fertige PCL-Dokumente liefert und daraus erstelle ich mit der Hilfe von VeryPDF die PDFs. Aber der von dir empfohlene Link bringt mich auf andere Ideen und ich werde sicher darauf zurück kommen.

Du kannst ein neues Visual Studio Projekt erstellen, den COM-Verweis für das ActiveX-Control einfügen und Dir die Methoden ganz normal im Visual Studio Objektbrowser ansehen.

Ansonsten gibt es das Adobe Reader Developer Center:
>

Ich habe mir die Methoden so angeschaut und festgestellt, dass diese in der Doku unter http://livedocs.adobe.com/acrobat_sdk/9.1/Acrobat9_1_HTMLHelp (nach "AxAcroPDFLib.AxAcroPDF" suchen) beschrieben sind.

Ist AcroPDF das einzige Bestandteil dieses SDK, welches man kostenlos nutzen darf?

Gibt es überhaupt eine Möglichkeit, die PDF-Datei zu laden und sie auf einem vorgegebenen Drucker (nicht Standarddrucker) direkt zu drucken, ohne dass der Anwender den Drucker über das Druckerdialogfeld auswählt?

Wenn das ginge, wäre AcroPDF für mich die ideale Methode.

Danke für die Blumen.

Nein, ich danke dir. Die hast du dir mehr als verdient.

René

2.760 Beiträge seit 2006
vor 12 Jahren

Hallo zusammen,

mit den aktuellen Versionen des Adobe Readers gibt es eine AccessViolationException wenn man innerhalb des Controls die Tab-Taste drückt und so wie es aussieht möchte Adboe das Problem auch nicht beheben.

Habe hier einen kleinen Workaround aus dem Adobe Support-Forum (AccessViolationException fatal error, Acrobat 9, AxAcroPDFLib, .NET, Win7) eingebaut:


/// <summary>
/// .NET Wrapper für Adobe Reader ActiveX-Steuerelement
/// </summary>
public class AdobeReaderControl : AxHost {

    protected override void WndProc(ref Message m) {
        if (m.Msg == 0x1450) // Bug wenn man im reader TAB drückt (AccessViolationException) http://forums.adobe.com/thread/530591
            return;
        base.WndProc(ref m);
    }

    /// <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>
    /// Lädt eine PDF-Datei.
    /// </summary>
    /// <param name="path">Pfad</param>
    public void LoadFile(string path) {
        // LoadFile-Methode auf dem Adobe Reader aufrufen
        this.GetOcx().GetType().InvokeMember("LoadFile", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, this.GetOcx(), new object[1] { path });
    }

    /// <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]);
    }
}

N
5 Beiträge seit 2012
vor 12 Jahren

Hallo allerseits,

ich schaffe es nicht, das Beispielprojekt zum laufen zu bringen! 😦

Die im Programm angegebene CLSID finde ich bei mir in der Registry. Allerdings habe ich keinen Acrobat 9, sondern die aktuelle Version "Adobe Reader X" Version 10.1.2.

Beim öffnen des Beispielprojektes in VS2010professional wird es erst mal konvertiert. Dabei gab es lt. Log keine Fehler oder Warungen.

Trotzdem kann ich AdobeReaderControl.cs nicht öffnen. Beim Versuch erhalte ich die Meldung "Der Designer kann keine Instanz des Typs System.Windows.Forms.AxHost erstellen, da dieser als abstrakt deklariert ist."

Starte ich das Programm trotzdem, so erhalte ich den Fehler "Klasse nicht registriert".

Für mich sieht es so aus, als wenn da ein Verweis fehlt.
Aber was muss da ggf. noch hinzugefügt werden?

Ich bin da etwas ratlos....

Caio,
N.

N
5 Beiträge seit 2012
vor 12 Jahren

Ich bin der Lösung näher gekommen:

Mir ist eingefallen, daß ich ja auf einem Windows 7 64-Bit-System entwickle. So startet der Compiler offensichtlich in der Standardeinstellung "Any CPU" offensichtlich eine 64-Bit-Version meines Programmes. Die hat wieder anscheinend ein Problem mit 32-Bit-Komponenten.

Nachdem ich nun in den Eigenschaften des Projektes auf Zielplattform "x86" geschaltet habe, funktioniert alles plötzlich einwandfrei!

Nun muss ich aber irgendwie eine Lösung für dieses Mischmasch finden, denn ich kann nicht verhindern, daß mein Programm auf 64-bit-Systemen läuft, wo irgendwann später auch mal ein 64-Bit-Adobe läuft. Das wird mit Sicherheit auch wieder nicht zusammen spielen...

Aber dieses Problem haben ja sicher auch viele andere Entwickler. Also hoffe ich mal, daß da noch eine Lösung zu auftaucht.

Ciao,
N.

M
94 Beiträge seit 2005
vor 8 Jahren

Ein altes Thema dass ich ausgrabe, aber dennoch brauche ich mal einen Tipp zu den Wrappern.

Ich benutze z.B. SetShowToolbar als Befehl an das ontrol, aber wenn ich es aufrufe, habe ich trpotzdem die Steuerungsleiste da von wo aus der benutzer kopien speichern und drucken kann.

Wie kann ich das ausblenden / abschalten?

Gleiches gilt für das Kontextmenü. Das sollte auch zu verhindern seinooder der inhalt anzupassen.

D
21 Beiträge seit 2017
vor 5 Jahren

Auch wenn dieser Thread schon sehr alt ist..
Wenn es hierführ mittlerweile eine Lösung gibt, ich wäre auch daran interessiert!

Danke!

M
3 Beiträge seit 2011
vor 4 Jahren

Also auch wenn der Beitrag schon alt ist - gibt es denn da inzwischen andere Lösungen?
Ich bekomme diese Beispiel auch nicht zum laufen.

Kann man sich denn den vom Wrapper erzeugten Code irgendwo ansehen, um ihn sich eventuell zunutze zu machen?