Von VBA zu VB.NET

Christoph Spielmann, Düsseldorf

Die Entwicklung von Anwendungen auf der .NET-Plattform gewinnt immer mehr an Bedeutung. Auch für Access-Entwickler stellt sich daher die Frage, ob bestimmte Anwendungen nicht besser mit .NET als mit Access entwickelt werden sollten. Dies trifft insbesondere auf moderne Anwendungen zu, die beispielsweise per Web-Service mit anderen Systemen kommunizieren, auf unterschiedliche Datenbank-Server zugreifen und das Benutzer-Interface im Web präsentieren. In diesem Artikel stellen wir Ihnen die .NET-Plattform genauer vor und zeigen Ihnen, wie Sie als VBA-Programmierer möglichst einfach auf VB.NET umsteigen können.

Wenn Sie eventuell schon einmal innerhalb von Access mit ActiveX-Steuerelementen gearbeitet haben, wurden Sie sicherlich mit Problemen bei der Weitergabe Ihrer Anwendung konfrontiert. Zum einen ist es erforderlich, dass der Ziel-PC das Microsoft-Office-Paket oder Access in der passenden Version installiert hat. Sollte dies nicht der Fall sein, bleibt Ihnen nur der Erwerb der Entwickler-Version von Access, die auch eine Laufzeitumgebung enthält.

Zudem ist es erforderlich, dass der Ziel-Rechner ebenfalls die bei der Entwicklung verwendeten ActiveX-Steuerelemente enthält. Da diese – anders als bei einer Access-Datenbankdatei – nicht einfach auf den Ziel-Rechner kopiert, sondern vorschriftsmäßig installiert und in der Registry eingetragen werden müssen, ist die Erstellung eines Setup-Programms erforderlich. Dies verursacht natürlich zusätzlichen Aufwand und bringt auch wieder Probleme mit sich, falls die ActiveX-Controls bereits auf dem Ziel-Rechner vorhanden sind, aber eine andere Versionsnummer haben. Sollte die vorhandene Version kleiner als die von Ihnen benötigte sein, funktioniert Ihre Anwendung eventuell nicht richtig. Wenn Sie die Version dagegen durch eine neuere ersetzen, könnten damit bereits vorhandene Anwendungen auf dem Ziel-Rechner unbrauchbar werden, da sie eine spezielle Version voraussetzen. Diese Problematik wird allgemein auch als “DLL-Hölle” bezeichnet. Sie führt dazu, dass viele Access-Entwickler komplett auf den Einsatz von Komponenten verzichten, sodass sie lediglich eine einfache MDB-Datei weitergeben müssen. Sie nehmen hierbei oft in Kauf, dass sie Funktionen, die von Komponenten zur Verfügung gestellt werden könnten, lieber in VBA nachprogrammieren, da dies das geringere übel bedeutet.

Alle beschriebenen Einschränkungen haben ihren Ursprung in dem Komponentenmodell “COM” (Component Object Model) von Windows. Dies ist Basis aller klassischen Anwendungen aus dem Hause Microsoft wie zum Beispiel Word, Excel, Outlook oder Access.

Microsoft hat sich die Aufgabe gestellt, das komplette COM-Objektmodell durch ein neues Komponentenmodell zu ersetzen. Herausgekommen ist nach fast zehn Jahren Forschungs- und Entwicklungsarbeit die .NET-Plattform.

Das Besondere an der .NET-Plattform ist, dass sie in weiten Zügen unabhängig vom Betriebssystem und der darunter liegenden Hardware ist. Lediglich einige Kernbereiche nutzen Betriebssystemfunktionen. Dazu gehören beispielsweise der Zugriff auf das Dateisystem, die Kommunikation über das Netzwerk sowie die Darstellung der Benutzeroberfläche von Windows-Anwendungen.

Tatsächlich ist es so, dass ein Tochterunternehmen der Firma Novell bereits eine Version des .NET-Frameworks für Linux entwickelt hat. Ziel des Projekts “Mono” ist es, dass Anwendungen zwischen Linux und Windows ohne Neukompilierung ausgetauscht werden können.

Damit dies funktioniert, besetzt das .NET-Framework ein Modul namens “Common Language Runtime”, kurz CLR. Die CLR besitzt die Fähigkeit, einen Programmcode kurz vor der Ausführung in Anweisungen für das jeweilige Betriebssystem zu übersetzen. Die übersetzung wird auch als “Just In Time”-Kompilierung (kurz JIT) bezeichnet. Hierbei kann der Compiler den Programmcode zum Beispiel auf Ausführungsgeschwindigkeit oder auf geringen Platzbedarf optimieren. Wenn Sie also auf Ihrem PC etwa Word und Access gestartet haben, also wenig Hauptspeicher zur Verfügung steht, kann die CLR eine neu gestartete Anwendung möglichst Platz sparend kompilieren.

Das “Jitten” spielt auch beim Komponentenmodell eine wesentliche Rolle. Kurz vor dem Start prüft .NET, welche Komponenten von der Anwendung benötigt werden und ob diese in passenden Versionen zur Verfügung stehen. Sollte dies der Fall sein, wird die Anwendung kompiliert und fest mit den Komponenten verknüpft.

Dies benötigt zwar etwas Zeit beim Start der Anwendung, garantiert jedoch eine hohe Ausführungsgeschwindigkeit. Wird die Anwendung beendet und neu gestartet, beginnt der Vorgang von Neuem. Sollten nun neuere Komponenten zur Verfügung stehen, werden diese natürlich beim Neustart berücksichtigt.

Die bereits angesprochenen Komponenten werden unter .NET als “Assemblies” bezeichnet. Hierbei handelt es sich um Dateien, die aus zwei wesentlichen Bereichen bestehen: Dem Manifest und dem eigentlichen Programmcode. Das Manifest enthält hierbei Informationen zu dem Assembly. Dazu gehören etwa die Versionsnummer, die Namen der enthaltenen Klassen und deren Mitglieder sowie Text- und Grafik-Ressourcen. Jedes Assembly beschreibt sich selbst also möglichst gut, damit es von anderen Assemblies verwendet werden kann.

Assemblies haben in der Regel die Dateiendung DLL, obwohl sie nichts mehr mit den klassischen DLLs aus der COM-Welt zu tun haben. Ausnahme bilden direkt ausführbare Programme, die die Dateiendung EXE haben. .NET-EXE-Dateien enthalten im Kopf einen Boot-Bereich. Dieser teilt dem Betriebssystem mit, dass die EXE-Datei nicht auf herkömmlichem Wege gestartet, sondern an die CLR weitergeleitet werden soll. Diese nimmt dann den Start vor.

Vorher prüft sie noch die Herkunft des Assemblies und aktiviert entsprechende Sicherheitsfunktionen. Beispielsweise haben Assemblies, die aus dem Internet stammen, standardmäßig nur sehr wenig Rechte. Sie dürfen nicht auf das Dateisystem oder die Registry zugreifen, was die Ausbreitung von .NET-Viren zusammen mit den anderen Sicherheitsfunktionen von .NET nahezu unmöglich macht.

Wie bereits erwähnt, enthalten Assemblies neben dem beschreibenden Manifest auch den eigentlichen Programmcode; dieser liegt jedoch nicht in einer Hochsprache vor, sondern in einer Zwischen-Sprache. Diese trägt den Namen “Intermediate Language” – kurz “IL”.

Diese Sprache kann sehr einfach in Ausführungsanweisungen für den Prozessor übersetzt werden, was vom JIT-Compiler erledigt wird und eine hohe Performance garantiert.

Die Sprache ist daher sehr hardwarenah, was für den normalen Programmierer wenig Komfort bedeutet. Ein Beispiel finden Sie in Abb. 1.

Abb. 1: Beispiel für IL-Code

Praxis-Tipp

Wenn Sie selbst einmal einen Blick auf den IL-Code eines Assemblies werfen möchten, verwenden Sie das Tool ILDASM.EXE (s. Abb. 2), das zum Lieferumfang des .NET-SDKs gehört. Sie finden es im BIN-Ordner. Mit dem Menüpunkt File/Open können Sie ein beliebiges Assembly öffnen und das Manifest begutachten. Bei einem Klick auf einen Klassen-Member wird der IL-Code angezeigt.

Zur Vereinfachung der IL kommen Hochsprachen wie C# oder VB.NET ins Spiel. Ein mit diesen Sprachen erstellter Programm-Code wird mit Hilfe eines Kompilers zunächst in die IL übersetzt und zusammen mit dem Manifest in ein Assembly gepackt.

Dieses Assembly kann schließlich vom JIT-Kompiler in Maschinen-Code übersetzt und ausgeführt werden.

Andere Anbieter wie etwa Borland stellen ebenfalls Kompiler zur Verfügung, die beispielsweise die Programmiersprache “Delphi” in die IL übersetzen.

Da dies relativ einfach ist, gibt es inzwischen sehr viele unterschiedliche Sprachen für die .NET-Plattform. Die übersetzung der Hochsprache in die IL findet auf dem PC des Entwicklers statt, sodass dieser den Quellcode seiner Anwendung nicht weitergeben muss. Auf diese Weise kann er sein geistiges Eigentum schützen.

Hierbei gibt es jedoch eine Einschränkung: Microsoft wollte das Komponentenmodell möglichst effizient gestalten.

Abb. 2: Der Disassembly ILDASM

Zu diesem Zweck war es erforderlich, sehr viele Informationen über die Komponente im Manifest unterzubringen. Dazu zählen beispielsweise auch Namen von Klassen, Prozeduren und Eigenschaften.

Zusammen mit dem IL-Code ist es relativ einfach möglich, den originalen Quelltext zu rekonstruieren. Hierbei fehlen zwar einige Elemente wie etwa die Namen der lokalen Variablen; die Arbeitsweise des Quellcodes lässt sich jedoch gut nachvollziehen. Wenn Ihr Quellcode also zum Beispiel schützenswerte Algorithmen enthält, sollten Sie hierauf achten.

Da die CLR nur die rudimentären Funktionen zur Entwicklung einer Anwendung zur Verfügung stellt, enthält die .NET-Plattform eine Bibliothek aus über 4.000 Klassen. Diese können von Programmierern zur Lösung der verschiedensten Aufgaben eingesetzt werden. Diese Bibliothek wird häufig auch als “.NET-Framework” bezeichnet.

Das Framework erledigt neben einfachen Funktionen wie zum Beispiel die Umwandlung einer Zahl in einen Text auch komplexe Aufgaben wie die Kommunikation mehrerer Systeme untereinander mittels Web-Service.

Microsoft hat Wert darauf gelegt, dass für fast alle Alltagsaufgaben eine passende Klasse zur Verfügung steht. Wenn Sie also beispielsweise eine Liste aus Texten sortieren möchten, müssen Sie nicht zuerst einen Quick-Sort- oder Bubble-Sort-Algorithmus programmieren, sondern können direkt auf eine passende Klasse zurückgreifen. Der Nachteil: Es gibt so viele Klassen, dass Sie einige Zeit benötigen, bis Sie einen groben überblick über alle Funktionsbereiche erhalten. Um Ordnung in die Klassen zu bringen, hat Microsoft diese in “Namespaces” organisiert. Der Namespace “System.IO” enthält beispielsweise alle Klassen, die sich mit dem Lesen und Schreiben von Dateien beschäftigen. In “System.Windows.Forms” finden Sie dagegen alles Nötige, um Windows-Benutzeroberflächen zu entwerfen.

Das .NET-Framework ist komplett objektorientiert aufgebaut. Um dies zu verstehen, ist die Unterscheidung zwischen den Begriffen “Klasse” und “Objekt” wichtig: Eine Klasse existiert nur ein einziges Mal pro Anwendung. Sie dient als Schablone zur Erstellung eines Objekts. Wenn Sie also beispielsweise in einer Adressverwaltung zehn Personen mit den gleichen Attributen (Namen, Vorname, Ort, PLZ, …) verwalten möchten, programmieren Sie nicht zehn Objekte, sondern nur eine einzige Klasse, und erzeugen auf Basis dieser Klasse zehn Objekte.

Praxis-Tipp

Synonym für den Begriff “Objekt” steht auch der Begriff “Instanz”.

Das Erstellen einer eigenen Klasse können Sie zum Beispiel mit SharpDevelop ausprobieren. Dazu gehen Sie wie folgt vor:

  • Falls noch nicht geschehen, installieren Sie SharpDevelop und das .NET-Framework nach der Beschreibung des Beitrags .NET-Programmierung mit SharpDevelop aus Ausgabe 4/2004.
  • Starten Sie SharpDevelop.
  • Wählen Sie den Menüpunkt Datei/Neu/Combine aus.
  • Klicken Sie auf die Kategorie VBNET und die Schablone Konsolenanwendung.
  • Geben Sie unter Name den Projektnamen Personenverwaltung ein.
  • Bestätigen Sie mit Erstellen. (
  • Auf dem Bildschirm ist nun ein neues, leeres Projekt sichtbar. Starten Sie das Projekt testweise mit der Taste F5.

    Es erscheint ein Konsolenfenster auf dem Bildschirm, in dem der Text “Hello World” ausgegeben wird.

    Praxis-Tipp

    Konsolen-Anwendungen bieten nur eine eingeschränkte Benutzeroberfläche nach dem Vorbild von DOS. Der Vorteil ist, dass die komplexen Benutzeroberflächen-Klassen zunächst außen vor bleiben und der Einstieg in .NET damit leichter fällt.

    Zur Anlage der ersten Klasse gehen Sie wie folgt vor:

  • Klicken Sie im Projekt-Explorer von SharpDevelop den Eintrag Personenverwaltung mit der rechten Maustaste an. Wenn der Projekt-Explorer nicht sichtbar ist, hilft die Tastenkombination Strg + Alt + L weiter.
  • Wählen Sie den Menüpunkt Hinzufügen/Neue Datei aus.
  • Klicken Sie auf die Kategorie VB und die Schablone Klasse.
  • Geben Sie unter Dateiname den Text Person.vb ein.
  • Bestätigen Sie mit Erstellen. (
  • Im Quellcode-Editor erscheint nun der folgende Programmcode:

    Imports System
    Namespace Personenverwaltung
        Public Class Person
            Public Sub New()
            End Sub
        End Class
    End Namespace

    Die eigentliche Klasse beginnt mit der Zeile Public Class Person und endet mit End Class.

    Die komplette Klasse ist eingekapselt durch die Zeilen Namespace Personenverwaltung und End Namespace. Dies bedeutet, dass die neue Klasse zum Namespace Personenverwaltung gehört. Zur Erinnerung: Namespaces dienen der besseren Organisation von Klassen. So könnten Sie beispielsweise alle Klassen, die sich mit der Verwaltung von Personen beschäftigen, in den Namespace Personenverwaltung einordnen und alle Klassen zum Thema Projektverwaltung in den Namespace Projektverwaltung.

    Zu Beginn ist noch eine Imports-Anweisung angegeben. Diese bewirkt eine Abkürzung bei dem Verweis auf Klassen. Wenn Sie beispielsweise auf die Klasse System.IO.FileInfo zugreifen möchten, können Sie im Programmcode entweder mit

    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