Stand: 18. Mai 1997.
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.
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!
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:
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.
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):
Declare Function vbInp
Lib "VBASM.DLL" (ByVal nPort As
Integer) As Integer
Declare Sub vbOut Lib "VBASM.DLL"
(ByVal nPort As
Integer, ByVal nData As Integer)
Sub Main()
End Sub
[Allgemein] [Deklarationen]
Dim PortAddress As
Integer
Public Property Let Port(vNewValue
As Integer)
PortAddress = vNewValue
End Property
Public Property Get Port() As Integer
Port = PortAddress
End Property
Public Property Get ByteIO() As
Integer
ByteIO = vbInp(PortAddress)
End Property
Public Property Let ByteIO(vNewValue As
Integer)
vbOut PortAddress, vbnewvalue
End Property
Dim IO As Thunker.IO
Set IO = New Thunker.IO
IO.Port = &H90
MsgBox Hex$(IO.ByteIO)
Set IO = Nothing
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:IO.Port = &H90
IO.ByteIO = &HFF
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.