VB als 32/16bit-Bindeglied

Stand: 18. Mai 1997.

Einleitung

Eine der oft gestellten Fragen in der Usenet-Gruppe comp.lang.basic.visual.misc ist "Wie kann ich eine 16bit-DLL mit 32bit-VB benutzen?" Die Absicht dieses Artikels ist zu erklären, wie man Visual Basic 4 und OLE als bindendes Glied so einsetzen kann, daß 16bit-Komponenten von 32bit-VB aus benutzt werden können.

Hintergrundinformationen

Wie wir alle wissen begann Windows in der 16bit-Welt (tatsächlich war es eine 8bit-Welt, aber zu den Zeiten war Windows nicht besonders populär). Im 16bit-Modell, das mit Windows 3.0 eingeführt wurde, war Speicher für alle Anwendungen zugänglich und Hardware war ungeschützt. Einfach gesagt bedeutete dies, daß so ziemlich alle denkbaren low-level-Operationen möglich waren, aber gleichermaßen konnten sich Programme überschneiden und Werte in ein sensibles Hardware-Register schreiben, so daß das gesamte System abstürzte. Das typische Endresultat solcher Vorgänge waren die ab Windows 3.1 "Schutzverletzung" benannten Komplettabstürze.

Mit der Einführung von Windows NT wurde ein neues Modell gewählt, das auf 32bit-Instruktionen basierte, die nur ab 386er-Prozessoren zur Verfügung standen (bei der Einführung von Windows 3.0 waren 286er noch Standard). Aufgrund der weiter fortgeschrittenen Speicherverwaltung in 386ern konnte "protected memory" (geschützte Speicherbereiche) ermöglicht werden, der 32bit-Anwendungen gegenseitig schützte und Programmen den Zugriff auf Hardware verweigerte, soweit dies nicht vorgesehen war.

Um Entwickler vom 16bit- auf das 32bit-System ziehen zu können schuf Microsoft einen Ansporn mit dem "flat memory"-Modell, das die Benutzung von größeren als den 16bit-typischen 64kB-Speicherblöcken erlaubte sowie präemptives Arbeiten und eine Menge anderer Features beinhaltete.

Trotzdem: Durch die Programmierung in 32bit verloren die Programmierer die Möglichkeit, direkt mit Hardware zu kommunizieren oder 16bit-DLLs direkt zu benutzen (die natürlich wiederum direkt mit der Hardware kommunizieren könnten und somit das System zum Absturz bringen könnten). Während dies allen Programmierern einen harten Brocken in den Weg legt, die einen guten Grund zur direkten Hardware-Kommunikation haben, kann man durchaus von einem Fortschritt reden, da ein echtes 32bit-Betriebssystem wie Windows NT mit reinen 32bit-Anwendungen nicht abstürzt, wenn eine einzelne Anwendung wegschmiert. Der Windows NT-Server im Büro des Autors ist nur einmal innerhalb eines Jahres (oder mehr) abgestürzt - und das weil die Festplatte fehlerhaft war!

Mehr über Hardware-I/O

Da einer der Gründe für die Benutzung von 16bit-DLLs von 32bit-VB aus gerade low-level-I/O ist, hierzu noch ein kurzes Wort. Ohne eine ganze Menge Programmierarbeit können 32bit-Anwendungen nicht direkt mit Hardware kommunizieren. Für Windows 95 bedeutet dies das Schreiben eines VxD für den Kontakt zur Hardware, für Windows NT muß ein Gerätetreiber geschrieben werden. Beides erfordert das DDK (Device Driver Kit) und eine ganze Menge Ahnung, wie Windows intern funktioniert.

Da Microsoft die Abwärtskompatibilität von Windows 95 für 16bit-Anwendungen gewährleisten wollte kann dort 16bit-Code direkt mit Hardware kommunizieren. Für Windows NT jedoch gilt der gleiche Vorbehalt - keine Anwendung kann ohne einen Gerätetreiber direkt mit Hardware kommunizieren.

Es gibt eine Reihe kommerzieller Produkte für die 32bit-Entwicklung, die low-level-I/O entweder durch einen VxD oder Gerätetreiber ermöglichen, aber die sind bei weitem nicht billig. Hier einige derer, die der Autor beworben gesehen hat:

Zurück zur Problematik

OK, trotz aller Gründe, warum man eine 16bit-DLL nicht mit 32bit-VB benutzen kann und trotz der Tatsache, daß eine direkte Hardwarekommunikation nur unter Windows 95 funktionieren wird, wird man dies bei einigen Gelegenheiten wollen. Warum also nicht einfach die OLE-Technologie benutzen? Die wichtigste Voraussetzung ist Visual Basic 4 entweder in der Professional- oder in der Enterprise-Edition. Die Standard-Edition stellt nur die 32bit-Umgebung zur Verfügung und ist daher nicht geeignet.

Der nächste Schritt ist das Nachdenken über die Aufrufe an die DLL, die von der Anwendung benutzt werden sollen. Diese werden entweder Properties (Eigenschaften) oder Methods (Methoden) des 16bit OLE-Servers, der von der 32bit-Anwendung aus etwa wie jeder normale OLE-Prozeß benutzt wird.

Erstellung des 16bit-Servers

In diesem Beispiel benutzen wir Jonathan Wood's VBASM.DLL. Diese Freeware-DLL erlaubt 16bit-Anwendungen alle möglichen Low-Level-Operationen inklusive DOS-Interrupts, Hardware-I/O und so weiter. Dieser OLE-Server wird erlauben, jeden Hardware-Port auszulesen oder auf ihn zu schreiben.

Und so geht's (aus Kompatibilitätsgründen wurden die Bezeichnungen des englischen Original-Artikels beibehalten):

  1. VBASM (34 kB) downloaden und die DLL in das Windows\System-Verzeichnis kopieren.
  2. VB4 in der 16bit-Version starten. Form1 aus dem neuen Projekt entfernen (Datei, Datei entfernen) und über das Einfügen-Menü ein neues Modul sowie ein neues Klassenmodul einfügen.
  3. Auf der Property-Liste (Eigenschaften) des Klassenmoduls folgende Werte setzen:
  4. Nun ins Menü Extras, Optionen und die Registerkarte Projekt anwählen. Dort die folgenden Werte setzen:
  5. Mit OK bestätigen und jetzt ins Code-Fenster des Moduls wechseln um folgenden Code einzufügen:

  6. Anwählen des IO-Klassenmoduls und nach "Einfügen, Prozedur" im Name-Feld "Port" eingeben. Der Typ wird auf "Property" gesetzt.
  7. Diese Prozedur (Schritt 7) muß nun wiederholt werden: Diesmal wird als Name "ByteIO" gewählt, der Typ ist wiederum "Property".
  8. Nun im IO-Klassenmodul folgenden Code einfügen:

  9. Das Projekt speichern. Die folgenden Schritte sind besonders wichtig:
  10. Nun kann die16bit-Version von VB4 verlassen werden.

Erstellung des 32bit-Clients

  1. Die 32bit-Version von VB4 starten. Ein neues Projekt erzeugen und mittels Extras, Verweise in das Referenzen-Fenster wechseln. Die Liste herunterscrollen und den Eintrag "Low Level I/O" auswählen.
  2. Auf Form1 einen Button anbringen und den folgenden Code hinzufügen:

  3. Das ist so ziemlich alles. Das Setzen von IO.Port wählt die Schnittstelle an, mit der kommuniziert werden soll. Das Auslesen von IO.ByteIO liest die Schnittstelle aus und das Setzen eines Wertes mittels IO.ByteIO schreibt auf die Schnittstelle, zum Beispiel:

Abschließende Bemerkungen

Der Grund, aus dem das 16bit-Projekt zweimal compiliert wird (einmal als bServer.EXE und einmal als ioserver.EXE) ist der, das die GUID des OLE-Servers nicht jedesmal geändert wird. Beim Compilieren eines OLE-Automations-Servers wird eine neue GUID (Globally Unique ID) generiert, es sei denn, das Feld "Kompatibler OLE-Server" ist ausgefüllt. Dies bedeutet, daß bei jedem neuen Compilieren ohne den Eintrag in diesem Feld die GUID anders lauten würde und dann eine Re-Referenzierung des OLE.-Servers in jedem benutzenden Projekt notwendig wäre - was eine Höllenarbeit wäre. Nähere Informationen zu dieser Problematik finden sich in der Microsoft Knowledge-Base, Artikel-ID Q129869.

Außerdem sollte bemerkt werden, daß bei jedem Click auf den Befehlsbutton der OLE-Server erzeugt, benutzt und dann entfernt wird. Beläuft sich die Benutzung des OLE-Servers auf einen größeren oder häufigeren Umfang, so sollte die IO-Objekt-Variable auf Form-Ebene dimensioniert werden und die Erschaffung des OLE-Servers sollte im Form_Load-Event (Ereignis) durchgeführt werden. Das Entfernen des OLE-Servers sollte dann (z.B. Set IO = Nothing) im Form_Unload-Event plaziert werden.

Der Autor hofft, daß dieser Artikel verständlich erklärt hat, wie man 16bit-Komponenten unter Windows 95 von 32bit-VB aus benutzen kann. Diese Methode ist nicht unbedingt rasend schnell, aber sie funktioniert und ist in jedem Fall eine wesentlich bessere Alternative als die Unmöglichkeit dieses Zugriffs.


Copyright © 1996 Rod Hewitt - Übersetzt und zur Verfügung gestellt mit freundlicher Genehmigung des Autors von Mathias Schiffer.