Bedingte Kompilierung am Beispiel des PDF-Exports

Mit Access 2007 ist wieder mal eine neue Version erschienen. Damit stellt sich für Softwareentwickler und auch für Anwender die Frage, ob man zu dieser Version wechseln sollte oder vielleicht versucht, eine Anwendung so weit anzupassen, dass diese auch mit der neuen Version zusammenarbeitet und gleichzeitig die vorhandenen Versionen unterstützt. Wie sich das für einzelne Features umsetzen lässt, zeigen wir am Beispiel PDF-Export.

Eine Anwendung bauen, die unter Access 2003 und älter und auch unter Access 2007 läuft Was soll das bringen und vor allem: Wie soll das funktionieren Bei früheren Versionswechseln sah man sich in der Regel nicht solch gravierenden Neuerungen ausgesetzt wie es jetzt unter Access 2007 der Fall ist. Das gilt natürlich insbesondere für das Ribbon, das die bisher verwendeten Menüleisten ersetzt. Aber auch unter VBA und in anderen Bereichen sind einige Features hinzugekommen.

Wir haben uns den PDF-Export vorgenommen, der unter Access 2003 und älter und unter Access 2007 auf unterschiedliche (kostenlose) Weise erfolgen kann, um zu untersuchen, wie man eine Anwendung für mehrere Access-Versionen und deren Eigenarten vorbereitet.

Lebans vs. Microsoft

Bis Office 2007 erschien und mit ihm ein Add-In, das den Export von Access-Berichten und auch von Office-Dokumenten ins PDF-Format erlaubte, konnte man sich entweder bei einer der kostenpflichtigen Lösungen bedienen oder etwas Handgemachtes einsetzen. Für Access-Berichte haben viele Entwickler zu einer Lösung von Stephen Lebans gegriffen (http://www.lebans.com/reporttopdf.htm). Diese Lösung verwendet zwei DLLs, die man einfach im Systempfad speichert und vom Programmcode aus aufruft. Details dazu erfahren Sie im Beitrag Vom Bericht zum PDF-Dokument (Shortlink 430).

Ab Access 2007 bietet Microsoft unter folgendem Link ein Add-In an, mit dem man wahlweise über einen Eintrag des Office-Menüs oder über den Befehl DoCmd.OutputTo ein Objekt (in der Regel einen Bericht) im PDF-Format speichert: http://www.microsoft.com/downloads/details.aspxdisplaylang=de&FamilyID=f1fc413c-6d89-4f15-991b-63b07ba5f2e5

Alles in einem

Für beide Lösungen ist eine gewisse Menge Code notwendig. Wenn Sie die Anwendung unter Access 2003 kompilieren, möchten Sie normalerweise nur den dafür nötigen Code dort unterbringen, unter Access 2007 sieht das genauso aus.

VBA bietet für solche Fälle die bedingte Kompilierung an. Damit können Sie für ein Modul eine Konstante festlegen und in Abhängigkeit vom Wert dieser Konstanten in einer speziell markierten If…Then-Anweisung den jeweiligen Code unterbringen. Das sieht etwa so aus:

#Const AccessVersion = 2000
Public Sub BeispielBedingteKompilierung()
#If AccessVersion = 2000 Then
    MsgBox "2000"
#ElseIf AccessVersion = 2007 Then
    MsgBox "2007"
#End If
End Sub

Im aktuellen Fall, also mit dem Konstantenwert 2000, wird Access die erste MsgBox-Anweisung ausführen.

Der Unterschied zu einer herkömmlichen If…Then-Bedingung und der Clou an der Sache ist, dass VBA nur den Teil des Codes kompiliert, der beim aktuellen Wert der Konstanten AccessVersion angesprungen wird. Das bedeutet, dass die .mdb/.accdb-Datei zwar den kompletten Code im Rohformat enthält (also das, was Sie auch im VBA-Editor sehen, auch kanonischer Code genannt), aber nur den Teil in kompilierter Fassung (P-Code), den Sie durch die #If…#Then-Bedingung zur bedingten Kompilierung freigegeben haben. Wenn Sie schon die gleiche Funktion für zwei verschiedene Access-Versionen im Projekt haben, brauchen Sie ja nicht auch noch das Kompilat des jeweils nicht benötigten Teils mitzuschleppen.

Noch besser wird es, wenn Sie eine .mde/.accde-Datenbank aus der Originaldatenbank erzeugen: Hier wirft Access ja bekanntlich den kompletten kanonischen Code raus und behält nur den P-Code. Auf unser Beispiel bezogen fällt, wenn Sie beispielsweise eine Version für Access 2000 bis 2003 kompilieren, der Code weg, der für die Ausgabe von PDFs mit dem Microsoft'schen Add-In nötig war.

Pro Modul

Leider ist die Gültigkeit der Konstanten für die bedingte Kompilierung auf ein Modul beschränkt, und es gibt auch immer nur eine solche Konstante. Dabei spielt es allerdings keine Rolle, ob Sie die Konstante innerhalb einer Routine oder im Modulkopf festlegen. Es ist sogar egal, ob Sie die #If…#Then-Anweisung zur bedingten Kompilierung innerhalb oder außerhalb von Routinen unterbringen. Das kann zum Beispiel auch so aussehen:

Public Sub Test()
#Const AccessVersion = 2000
End Sub
#If AccessVersion = 2000 Then
Public Sub BeispielBedingteKompilierung()
    MsgBox "2000"
End Sub
#ElseIf AccessVersion = 2007 Then
Public Sub BeispielBedingteKompilierung()
    MsgBox "2007"
End Sub
#End If

In diesem Beispiel gibt es dieselbe Routine gleich zweimal. Welche der beiden ausgeführt wird, entscheidet der Wert der Konstanten AccessVersion, die sich hier einmal innerhalb einer Routine befindet. Der Grund für die lockere Handhabung ist, dass VBA sich vor dem Kompilieren zunächst die mit dem Raute-Zeichen (#) beginnenden Zeilen ansieht und rauswirft, was nicht kompiliert werden soll. In diesem Fall liefert der Aufruf der Routine BeispielBedingteKompilierung erwartungsgemäß den Wert 2000.

Globale Konstante

Wenn sich der bedingt zu kompilierende Code über mehrere Module verteilt, bedeutet das Kompilieren für verschiedene Versionen auf die Dauer viel Arbeit. Zum Glück gibt es eine Einstellung in den Eigenschaften eines VBA-Projekts, mit der Sie eine globale Konstante für diesen Zweck festlegen können. Diese Einstellung finden Sie im Eigenschaften-Dialog des VBA-Projekts (Extras|Eigenschaften von <Projektname>…).

Löschen Sie zunächst die entsprechende Zeile aus dem VBA-Code und probieren Sie, ob die bedingte Kompilierung noch wie erwartet arbeitet. Da die Routine BeispielBedingteKompilierung nur aufgerufen werden dürfte, wenn die Konstante den Wert 2000 oder 2007 enthält, sollte nun eine Fehlermeldung erscheinen, da überhaupt kein Wert festgelegt ist.

Tragen Sie nun im Eigenschaftsfenster unter Argumente für bedingte Kompilierung den Ausdruck ein, den Sie normalerweise im VBA-Code hinter #Const eingefügt haben (siehe Bild 1). Ein erneuter Aufruf von BeispielBedingteKompilierung dürfte nun wieder funktionieren und das Meldungsfenster mit der entsprechenden Versionsnummer anzeigen. Somit können Sie zumindest eine globale Konstante festlegen, statt diese gegebenenfalls in mehreren Modulen ändern zu müssen.

pic001.tif

Bild 1: Das Eigenschaftsfenster eines VBA-Projekts

Dynamische bedingte Kompilierung

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar