Variable in VB 6.0 verwenden deren Namen als Zeichenketten bekannt sind

Veröffentlicht: 19. Jan 2003 | Aktualisiert: 23. Jun 2004

Von Mathias Schiffer

Die Microsoft Newsgroups sind eine Quelle schier unerschöpflichen Wissens, das nahezu auf Knopfdruck abrufbar ist: Hunderte deutschsprachige Entwickler vom Einsteiger bis zum Profi treffen sich hier täglich virtuell, um Fragen zu stellen oder zu beantworten. Auch themennahe Probleme, Ansichten und Konzepte werden miteinander diskutiert. Sie kennen die Microsoft Newsgroups noch nicht? Detaillierte Information für Ihre Teilnahme finden Sie auf der Homepage der Microsoft Support Newsgroups.

Diese Kolumne greift regelmäßig ein besonders interessantes oder häufig nachgefragtes Thema aus einer der Entwickler-Newsgroups auf und arbeitet es aus.

Auf dieser Seite

 Aus der Visual Basic Newsgroup microsoft.public.de.vb:
 Eine Klasse als Variablenträger
 Sonderfall: Globale Variable
 CallByName als Lösungshilfe

Aus der Visual Basic Newsgroup microsoft.public.de.vb:

Wie kann ich in Visual Basic 6.0 eine Variable zur Programmlaufzeit mit einem Wert belegen oder ihren Wert auslesen, wenn mir der Name der Variablen als String vorliegt (z.B. durch eine Benutzereingabe)?

Die Frage selbst lässt sich recht einfach beantworten: Diese Möglichkeit besteht nicht. Variablen sind lediglich Platzhalter für logische Speicherplätze, deren Werte grundsätzlich geändert werden können.

Der Name einer Variablen ist für den Compiler gänzlich bedeutungslos. Er benötigt nicht die Hilfe, die ein menschlicher Programmierer durch die Verwendung von Variablen in Anspruch nimmt, sondern ordnet beim Compilieren allen Variablen relative Speicheradressen zu. In einer compilierten Anwendung existieren Variablennamen daher gar nicht mehr, so dass ein Zugriff auf Variable über ihre Namen zur Laufzeit bereits definitorisch nicht möglich ist.

Um den angestrebten Zweck zu erreichen, lassen sich jedoch andere Lösungskonzepte einsetzen.

 

Eine Klasse als Variablenträger

Nicht nur in Variablen lassen sich Werte verwalten. Auch Eigenschaften einer instanzierten Klasse eignen sich hierfür funktional mindestens gleichwertig. Im Unterschied zu Variablennamen kennt Visual Basic die Namen der Eigenschaften, Methoden und Funktionen von Objekten auch zur Laufzeit.

Nehmen Sie für einen kurzen Moment einmal an, Visual Basic würde keine Variablen anbieten (wie dargelegt fallen sie zur Lösung des gestellten Problems ohnehin weg). Wo würden Sie dann Werte im Speicher halten?

Sie könnten etwa die Eigenschaften eines Labels-Steuerelements dafür verwenden: So ist die Caption-Eigenschaft eines Label-Steuerelements ein Beispiel für eine Eigenschaft vom Typ String, die sich statt einer String-Variablen verwenden ließe. Die Visible-Eigenschaft des Labels könnte als Ersatz für eine Boolean-Variable verwendet werden, etc. pp. - weitere Beispiele zu finden fällt nicht schwer.

Der grundsätzliche Unterschied zwischen Variablen und Eigenschaften aus der Sicht der Datenspeicherung ist, dass ein Objekt involviert ist (im Beispiel das Label-Steuerelement). Die Aufgabe, Werte entsprechender Typen zu speichern und diese wieder herauszugeben, kommen beiden Varianten gleichwertig nach.

Sicherlich wird niemand ernsthaft ein Label-Steuerelement als Ersatz für verschiedene Variablen verwenden wollen. Jedoch können Sie eine eigene Klasse mit entsprechenden Datentypen anlegen. Im einfachsten aller möglichen Fälle definieren Sie darin schlicht alle benötigten Variablen unter Zuweisung des entsprechenden Datentyps als Public - so legt VB im Verborgenen ein entsprechendes Property Get/Let/Set-Gerüst an, das für das Auslesen und Setzen des Eigenschaftenwertes von außen heraus zuständig ist.

' -------------------------- 
' Klassenmodul "clsVariable" 
' -------------------------- 
Option Explicit 
' Öffentliche Deklaration benötigter 
' Variabler, VB besorgt den Rest: 
Public strVorname As String 
Public strNachname As String 
Public lngGeburtsjahr As Long 
' --------------------------

Um die Eigenschaften eines Objekts des Typs clsVariable nutzen zu können, instanzieren Sie die Klasse mithilfe einer Objektvariablen, die in dem Gültigkeitsraum deklariert wird, in dem Sie auch Ihre Variablen selber deklariert hätten. Über diese Objektvariable können Sie nun Werte setzen und auslesen.

' Einfaches Anwendungsbeispiel: Form1 
Option Explicit 
' Modulweite Dimensionierung 
Dim ModulweiteVariable As clsVariable 
Private Sub Form_Initialize() 
  ' Instanzierung des modulweit gültigen Objekts 
  Set ModulweiteVariable = New clsVariable 
  ' Beispielhafte Verwendung 
  ModulweiteVariable.strVorname = "Billy" 
  Debug.Print ModulweiteVariable.strVorname 
End Sub 
Private Sub Form_Load() 
' Prozedurweite (lokale) Dimensionierung 
Dim LokaleVariable As clsVariable 
  ' Instanzierung des prozedurweit gültigen Objekts 
  Set LokaleVariable = New clsVariable 
  ' Beispielhafte Verwendung 
  LokaleVariable.strVorname = "Howard" 
  Debug.Print "Lokal: " & LokaleVariable.strVorname 
  Debug.Print "Modul: " & ModulweiteVariable.strVorname 
End Sub

 

Sonderfall: Globale Variable

Möchten Sie globale Variable auf diese Weise verwenden, können Sie sich sogar die Dimensionierung, die Instanzierung und sogar die Verwendung des Klassennamens bei Setzen und Abfragen der Eigenschaften ersparen. Hierfür legen Sie ein ActiveX DLL-Projekt an, geben dem standardmäßig zur Verfügung gestellten Klassenmodul einen entsprechenden Namen (etwa "clsGlobaleVariable") und setzen ihre Eigenschaft Instancing im Eigenschaftenfenster auf "6 - GlobalMultiUse".

Im Quelltext der Klasse legen Sie wie gehabt ihre Eigenschaften im einfachsten Fall als Public-Variable an und compilieren die DLL anschließend (vergeben Sie im Projekteigenschaftenfenster eine passende Beschreibung und einen Namen für das Projekt, um es später einfacher identifizieren zu können).

In Ihrem nutzenden Projekt fügen Sie dann die soeben erstellte ActiveX DLL über den "Verweise"-Dialog des Projekt-Menüs hinzu. Nun können Sie die Eigenschaften der Klasse wie globale Variable in Ihrem Sourcecode verwenden:

' Beispielhafte Verwendung 
strVorname = "Howard" ' Abkürzend statt _ 
 ' clsGlobaleVariable.strVorname 
Debug.Print "Global: " & strVorname

Zwar ist dieses Vorgehen bequemer als die vorherigen Varianten, so dass man versucht sein könnte, gleich alle Variablen so zu verwenden, die später über ihren Namen als String angesprochen werden sollen. Sie sollten jedoch nicht außer Acht lassen, dass auf diese Weise ausschließlich globale Variable ersetzt werden können. Der wertvolle Schutzmantel der eingeschränkten Gültigkeit lokaler Variabler steht mit dieser Möglichkeit nicht zur Verfügung.

 

CallByName als Lösungshilfe

Bisher wurde beschrieben, wie Sie echte Variablen in Ihrem Sourcecode durch Eigenschaften selbstdefinierter Objekte ersetzen können. Begründet wurde dieser Umweg über den Umstand, dass Visual Basic die Namen von Eigenschaften, Methoden und Funktionen von Objekten kennt. Was noch fehlt ist eine konkrete Möglichkeit, diesen Vorteil zum erwünschten Zweck zu nutzen.

Eine der Neuigkeiten von Visual Basic 6.0 war die Funktion CallByName: Mit ihrer Hilfe können Sie Eigenschaften, Funktionen und Methoden von Objekten über deren Namen ansprechen. Im Objektkatalog wird sie so geführt:

Function CallByName(Object As Object, ProcName As String, _ 
  CallType As VbCallType, Args() As Variant)

Als ersten Parameter Object wird CallByName eine Objektvariable übergeben, die auf das betroffene Objekt verweist. Im zweiten Parameter ProcName können Sie den Namen einer Eigenschaft, Funktion oder Methode dieses Objekts als String angeben. Im dritten Parameter CallType bestimmen Sie die gewünschte Aufrufkonvention mit den vordefinierten Konstanten vbLet (Setzen einer Eigenschaft), vbGet (Auslesen einer Eigenschaft), vbSet (Setzen einer Objekteigenschaft) oder vbMethod (Aufruf einer Methode oder Funktion). Beim Auslesen von Eigenschaften und Aufrufen von Funktionen entspricht der Rückgabewert von CallByName dem Wert der Eigenschaft bzw. dem Rückgabewert der aufgerufenen Funktion.

CallByName ermöglicht es also unter anderem, Werte von Eigenschaften eines Objekts auszulesen und zu setzen, wenn die Namen dieser Eigenschaften nur als Zeichenketten bekannt sind. Nachdem die Variablen, für die dies möglich sein soll, im ersten Schritt durch Eigenschaften von Klassen ersetzt wurden, bedarf es nun also nur noch eines entsprechenden Aufrufs dieser Funktion.

Der folgende, zum obigen Anwendungsbeispiel analoge Sourcecode verwendet alle Eigenschaften mithilfe der CallByName-Funktion ausschließlich über ihre Namen als Strings, statt sie direkt als Eigenschaften der zugehörigen Objekte zu verwenden:

' Einfaches Anwendungsbeispiel: Form1 
Option Explicit 
' Modulweite Dimensionierung 
Dim ModulweiteVariable As clsVariable 
Private Sub Form_Initialize() 
Dim Variablenname As String 
  ' Instanzierung des modulweit gültigen Objekts 
  Set ModulweiteVariable = New clsVariable 
  ' Zur Belegung der Eigenschaft verwenden wir statt 
  ' ModulweiteVariable.strVorname = "Billy" 
  ' CallByName unter Nutzung des Strings "strVorname": 
  Variablenname = "strVorname" 
  CallByName ModulweiteVariable, Variablenname, VbLet, "Billy" 
  ' Zum Auslesen der Eigenschaft verwenden wir statt 
  ' Debug.Print ModulweiteVariable.strVorname 
  ' CallByName unter Nutzung des Strings "strVorname": 
  Debug.Print CallByName(ModulweiteVariable, _ 
 Variablenname, VbGet) 
End Sub 
Private Sub Form_Load() 
Dim Variablenname As String 
' Prozedurweite (lokale) Dimensionierung 
Dim LokaleVariable As clsVariable 
  ' Instanzierung des prozedurweit gültigen Objekts 
  Set LokaleVariable = New clsVariable 
  ' Zur Belegung der Eigenschaft verwenden wir statt 
  ' LokaleVariable.strVorname = "Howard" 
  ' CallByName unter Nutzung des Strings "strVorname": 
  Variablenname = "strVorname" 
  CallByName LokaleVariable, Variablenname, VbLet, "Howard" 
  ' Zum Auslesen der Eigenschaft verwenden wir statt 
  ' Debug.Print "Lokal: " & LokaleVariable.strVorname und 
  ' Debug.Print "Modul: " & ModulweiteVariable.strVorname 
  ' CallByName unter Nutzung des Strings "strVorname": 
  Debug.Print "Lokal: " & CallByName(LokaleVariable, _ 
 Variablenname, VbGet) 
  Debug.Print "Modul: " & CallByName(ModulweiteVariable, _ 
 Variablenname, VbGet) 
End Sub

Auch hier stellen die globalen Eigenschaften einer GlobalMultiUser-Klasse eine Ausnahme dar: Zwar können Sie diese Eigenschaften ohne die Verwendung einer Objektvariablen belegen und auslesen. Die CallByName-Funktion ist jedoch auf die Übergabe einer Objektvariablen zwingend angewiesen.

Doch auch diesem Problem kommen Sie leicht bei: verwenden Sie als Objektvariable die globale Objektvariable, die Visual Basic im Hintergrund aufgrund der Instancing-Eigenschaft GlobalMultiUserGlobalMultiUser automatisch für Sie zur Verfügung gestellt hat: Sie entspricht dem Klassennamen, den Sie in Ihrem ActiveX DLL-Projekt vergeben hatten (im Beispielfall: "clsGlobaleVariable"). Die CallByName-Aufrufe zur Verwendung von Eigenschaften über deren Namen als String gestalten sich auch hier analog:

' Belegen einer Eigenschaft eines GlobalMultiUse-Objekts 
CallByName clsGlobaleVariable, Variablenname, VbLet, "Roderick" 
' Auslesen einer Eigenschaft eines GlobalMultiUser-Objekts 
Debug.Print CallByName(clsGlobaleVariable, Variablenname, VbGet)