Umgebungsvariable mit Visual Basic auslesen und setzen

Veröffentlicht: 03. Apr 2002 | Aktualisiert: 21. Jun 2004

Von Mathias Schiffer

Dieser Artikel zeigt, wie Sie mit Visual Basic Umgebungsvariable auslesen und setzen können. Umgebungsvariable kennen Sie sicher aus der Startdatei AUTOEXEC.BAT.
Der wohl bekannteste Vertreter der Umgebungsvariablen ist PATH. Sie hat Einfluss darauf, welche Verzeichnisse neben den standardmäßigen Windows-Verzeichnissen durchsucht werden, wenn eine Datei geladen wird.

Auslesen bestehender Umgebungsvariabler

Unter Visual Basic ist die Funktion Environ$ dafür zuständig, den Wert einer gesetzten Umgebungsvariablen auszulesen (sie kapselt die API-Funktion GetEnvironmentVariable:

MsgBox "Die Umgebungsvariable PATH hat den folgenden Wert:" & vbNewLine & vbNewLine & _ 
       Environ$("PATH"), _ 
       vbOKOnly Or vbInformation, _ 
       "Umgebungsvariable PATH"

TIPP: Nützlich für die tägliche Arbeit ist auch die Umgebungsvariable COMSPEC, die den Pfad zum verwendeten Kommandozeileninterpreter enthält.
Unter Windows 9x/Me ist das standardmäßig COMMAND.COM, unter Windows NT und seinen Vettern Windows 2000 und Windows XP die Datei CMD.EXE.Die Verwendung der Umgebungsvariablen COMSPEC isoliert Ihren Code von diesem Unterschied. Den Befehlszeileninterpreter müssen Sie immer dann aufrufen, wenn Sie einen DOS-Befehl ausführen möchten, der nicht als separat ausführbare Datei vorliegt. Ein Beispiel wäre die Dir-Befehl, um Ordner-Inhalte zu ermitteln.

' strDosBefehl enthält den "DOS-Befehl" so, wie Sie ihn 
' in einem Konsolenfenster eingeben würden: 
Dim strDosBefehl As String 
' Der Zeilenschalter "/C" bewirkt, dass das Konsolenfenster 
' automatisch geschlossen wird, wenn die darin auszuführende 
' Aufgabe abgearbeitet wurde: 
Const CloseConsoleWhenDone As String = " /C " 
' "DOS-Befehl" definieren... 
strDosBefehl = "Dir c:\*.* | more" 
' ... und ausführen: 
Shell Environ$("COMSPEC") & CloseConsoleWhenDone & strDosBefehl

Wird die Funktion Environ$ hingegen mit einem numerischen Argument aufgerufen, liefert sie auf Basis der API-Funktionen GetEnvironmentStrings und FreeEnvironmentStrings jeweils eine Umgebungsvariable mitsamt ihrem Wert in alphabetischer Reihenfolge der Variablennamen zurück. So können Sie alle definierten Umgebungsvariablen ermitteln:

Dim i As Long 
Dim strEnvironVars As String 
  ' Alle definierten Umgebungsvariablen ermitteln und 
  ' im String strEnvironVars ansammeln: 
  i = 1 
  Do While LenB(Environ$(i)) > 0 
    strEnvironVars = strEnvironVars & Environ$(i) & vbNewLine 
    i = i + 1 
  Loop 
  ' Wegschneiden des letzten angehängten Zeilenumbruchs (vbNewLine): 
  If LenB(strEnvironVars) > 0 Then 
    strEnvironVars = Left$(strEnvironVars, Len(strEnvironVars) - 2) 
  End If 
  ' Ausgabe des Resultats als MessageBox 
  MsgBox "Die folgenden Umgebungsvariablen sind definiert:" & vbNewLine & vbNewLine & _ 
         strEnvironVars, _ 
         vbInformation, _ 
         "Definierte Umgebungsvariable"

Prozessweit gültige Umgebungsvariable setzen

Arbeiten Sie mit Windows NT (oder Folgeversionen), können Sie Umgebungsvariable im Windows-Explorer mithilfe des System-Applets der Systemsteuerung zur Laufzeit einsehen und sogar neue Umgebungsvariable definieren. Sie werden feststellen, dass Windows NT sogar zwei unterschiedliche Arten von Umgebungsvariablen kennt: systemweit und für den jeweils angemeldeten Benutzer gültige Umgebungsvariable.
Unter Windows 9x/Me hingegen haben Sie weder die Möglichkeit, Umgebungsvariable zur Windows-Laufzeit systemweit zu setzen, noch wird hier zwischen den obigen Typen von Umgebungsvariablen unterschieden.

Allen angesprochenen Windows-Versionen ist jedoch gemeinsam, dass Sie eine Umgebungsvariable für Ihren Prozess (i.A. entspricht das Ihrer Anwendung) setzen können.

Hierfür bietet sich die API-Funktion SetEnvironmentVariable an. Möglicherweise fragen Sie sich, warum Sie diese Funktion statt einer anwendungsweit gültigen Variablen verwenden sollten, wenn sie ohnehin nur in Ihrer Anwendung Gültigkeit erlangt? Tatsächlich ist diese Implikation nicht voll zutreffend, denn auch Prozesse, die von Ihrem Prozess aus gestartet werden, teilen sich diese Umgebungsvariable mit Ihrem Prozess.

So können Sie über Umgebungsvariable Werte an Anwendungen übergeben, die Sie selbst aus Ihrem Prozess heraus starten. Bereits laufenden Prozessen - inklusive solcher, die Sie selber gestartet haben - können Sie mit SetEnvironmentVariable jedoch keine Daten übergeben.

Die Anwendung von SetEnvironmentVariable ist denkbar einfach:

' --- Prototyp-Deklaration von SetEnvironmentVariable: 
Private Declare Function SetEnvironmentVariable _ 
  Lib "kernel32" Alias "SetEnvironmentVariableA" ( _ 
  ByVal EnvironmentVariableName As String, _ 
  ByVal EnvironmentVariableValue As String _ 
  ) As Long 
' --- Code 
Dim lSuccess As Long 
  ' Umgebungsvariable für diesen Prozessraum einrichten: 
  lSuccess = SetEnvironmentVariable("VARIABLENNAME", "WERT DER VARIABLEN") 
  ' Erfolg überprüfen: 
  If lSuccess = 0 Then 
    ' Der Aufruf ist gescheitert. Eine Fehlernummer steht in Err.LastDllError zur Verfügung. 
    ' Um diese Fehlernummer in eine Fehlerbeschreibung im Klartext umzuwandeln, konsultieren 
    ' Sie bitte den Artikel "API Fehlermeldungen im Klartext" im "MSDN Quickie": 
    ' /germany/msdn/library/visualtools/vb6/APIFehlermeldungenImKlartext.mspx 
    MsgBox "Der Aufruf der Funktion SetEnvironmentVariable ist fehlgeschlagen." & vbNewLine & _ 
           "Der von Err.LastDllError gelieferte Fehlercode ist " & CStr(Err.LastDllError), _ 
           vbCritical, _ 
           "SetEnvironmentVariable fehlgeschlagen" 
  End If

Systemweite oder für den angemeldeten Benutzer gültige Umgebungsvariable setzen
Unter Windows 9x/Me können Sie systemweit gültige Variable setzen, indem Sie diese in der Datei AUTOEXEC.BAT definieren und Ihr System neu starten.
Wolleb Sie einen Neustart per Programm erreichen, konsultieren Sie bitte den Artikel "Windows 95, 98 und NT herunterfahren". Einen Mechanismus, dies zur Windows-Laufzeit zu erreichen, gibt es nicht. Ebenso existieren unter diesen Windows-Versionen keine benutzerspezifischen Umgebungsvariable.
Windows NT/2000/XP hingegen ermöglichen Ihnen sowohl das Anlegen von Umgebungsvariablen, als auch die Unterscheidung von systemweit und benutzerspezifisch gültigen Umgebungsvariablen. Für beide Arten von Umgebungsvariablen ist es erforderlich, die Variablennamen und ihre zugehörigen Werte in die Windows Registrierungsdatenbank ("Registry") einzutragen. Systemweit gültige Umgebungsvariable werden dafür unter dem Registry-Zweig HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\Environment geführt. Umgebungsvariable, die nur für den aktuell angemeldeten Benutzer gültig sein sollen, werden unter HKEY_CURRENT_USER\Environment hinterlegt.

Allein durch einen Eintrag in der Registry würden diese Umgebungsvariablen erst nach einem Windows-Neustart ausgelesen und gesetzt werden.
Um zu erreichen, dass nach dieser Änderung gestartete Anwendungen dennoch die neuen Variablen berücksichtigen, wird die Nachricht WM_SETTINGCHANGE mithilfe der Funktion SendMessageTimeout an alle Hauptfenster auf dem Desktop gesendet.
Als symbolisches Fensterhandle aller Empfänger wird dafür HWND_BROADCAST eingesetzt.
Auf bereits gestartete Anwendungen hat die Änderung jedoch keine Einwirkung.

Sourcecode: Umgebungsvariable setzen

Die folgende in Visual Basic geschriebene Funktion SetEnvironVar berücksichtigt die Unterschiede zwischen den verschiedenen Windows-Versionen und ermöglicht unter Windows NT/2000/XP, mit der Voraussetzung hinreichender Rechte des angemeldeten Benutzers, zudem das
Erzeugen einer entweder benutzerweit oder systemweit gültigen Umgebungsvariable. Zusätzlich setzt sie mithilfe der API-Funktion SetEnvironmentVariable die neue Umgebungsvariable auch prozessweit.

Die Aufgabe des Setzens einer Umgebungsvariable reduziert sich mit dieser Funktion betriebssystemunabhängig auf eine einzige Zeile, beispielsweise:

SetEnvironVar "UMGEBUNGSVARIABLE", "WERT DER VARIABLEN" 
' --- Deklarationen für die eingesetzten API-Funktionen 
Private Const WM_WININICHANGE         As Long = &H1A&   ' Änderung der Konfiguration 
Private Const WM_SETTINGCHANGE        As Long = WM_WININICHANGE 
Private Const SMTO_ABORTIFHUNG        As Long = &H2&    ' Abbruch bei Timeout 
Private Const HWND_BROADCAST          As Long = &HFFFF& ' Pseudo-Fensterhandle 
Private Const KEY_CREATE_SUB_KEY      As Long = &H4&    ' Registry-SubKey ggf. erzeugen 
Private Const KEY_SET_VALUE           As Long = &H2&    ' Registrywert setzen 
Private Const REG_SZ                  As Long = &H1&    ' Schlüsseltyp Zeichenfolge 
Private Const REG_OPTION_NON_VOLATILE As Long = &H0&    ' Registryeintrag persistent ändern 
Private Const ERROR_SUCCESS           As Long = &H0&    ' Erfolgreiche Abarbeitung 
Private Const VER_PLATFORM_WIN32_NT   As Long = &H2&    ' Das Betriebssystem ist eine NT-Version 
Private Enum REGISTRYKEYS ' Hauptschlüssel der Windows-Registry 
  HKEY_CLASSES_ROOT = &H80000000 
  HKEY_CURRENT_USER = &H80000001 
  HKEY_LOCAL_MACHINE = &H80000002 
  HKEY_USERS = &H80000003 
  HKEY_PERFORMANCE_DATA = &H80000004 
  HKEY_CURRENT_CONFIG = &H80000005 
  HKEY_DYN_DATA = &H80000006 
End Enum 
' Umgebungsvariable prozessweit setzen: 
Private Declare Function SetEnvironmentVariable _ 
  Lib "kernel32" Alias "SetEnvironmentVariableA" ( _ 
  ByVal EnvironmentVariableName As String, _ 
  ByVal EnvironmentVariableValue As String _ 
  ) As Long 
' Angaben zur Betriebssystemversion (GetVersionEx): 
Private Type OSVERSIONINFO 
  dwOSVersionInfoSize As Long 
  dwMajorVersion As Long 
  dwMinorVersion As Long 
  dwBuildNumber As Long 
  dwPlatformId As Long 
  szCSDVersion As String * 128 
End Type 
' Version des Betriebssystems ermitteln: 
Private Declare Function GetVersionEx _ 
  Lib "kernel32" Alias "GetVersionExA" ( _ 
  ByRef VersionInformation As OSVERSIONINFO _ 
  ) As Long 
' Einen Registry-Schlüssel erzeugen oder öffnen: 
Private Declare Function RegCreateKeyEx _ 
  Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _ 
  ByVal hKey As Long, _ 
  ByVal SubKey As String, _ 
  ByVal Reserved As Long, _ 
  ByVal Class As String, _ 
  ByVal Options As Long, _ 
  ByVal DesiredAccess As Long, _ 
  ByVal SecurityAttributes As Long, _ 
  ByRef hKeyResult As Long, _ 
  ByRef Disposition As Long _ 
  ) As Long 
' Einen Registry-Wert setzen: 
Private Declare Function RegSetValueEx _ 
  Lib "advapi32.dll" Alias "RegSetValueExA" ( _ 
  ByVal hKey As Long, _ 
  ByVal ValueName As String, _ 
  ByVal Reserved As Long, _ 
  ByVal TypeOfValue As Long, _ 
  ByRef Value As Any, _ 
  ByVal SizeOfValue As Long _ 
  ) As Long 
' Einen geöffneten Registry-Schlüssel schließen: 
Private Declare Function RegCloseKey _ 
  Lib "advapi32.dll" ( _ 
  ByVal hKey As Long _ 
  ) As Long 
' Fensternachrichten mit Timeout versenden: 
Private Declare Function SendMessageTimeout _ 
  Lib "user32" Alias "SendMessageTimeoutA" ( _ 
  ByVal hWnd As Long, _ 
  ByVal Message As Long, _ 
  ByVal wParam As Long, _ 
  ByRef lParam As Any, _ 
  ByVal Flags As Long, _ 
  ByVal Timeout As Long, _ 
  ByRef Result As Long _ 
  ) As Long 
' --- Funktion SetEnvironVar und von ihr verwendete Funktionen 
Public Function SetEnvironVar(ByVal VariableName As String, _ 
                              ByVal VariableValue As String, _ 
                              Optional ByVal Systemwide As Boolean = False _ 
                              ) As Boolean 
' Erzeugt eine neue, persistente Umgebungsvariable. 
' ----------------------------------------------------------------- 
' Parameterinformationen: 
' ----------------------------------------------------------------- 
' VariableName:  Name der neuen Umgebungsvariablen. 
' VariableValue: Wert der neuen Umgebungsvariablen. 
' Systemwide:    Legt fest, ob eine Benutzer-Umgebungsvariable oder 
' (nur WinNT)    eine System-Umgebungsvariable erzeugt werden soll. 
'                TRUE:  Es wird eine System-Umgebungsvariable erzeugt 
'                       (hinreichende Rechte vorausgesetzt). 
'                FALSE: Es wird eine Benutzer-Umgebungsvariable erzeugt. 
'                Dieser Parameter hat unter Windows 9x/Me keine Wirkung. 
' Rückgabewert:  TRUE bei Erfolg, FALSE bei Misserfolg. 
' ----------------------------------------------------------------- 
Dim OSVI As OSVERSIONINFO 
Dim ff As Integer 
  ' Prozesweites Setzen der Umgebungsvariablen: 
  SetEnvironmentVariable VariableName, VariableValue 
  ' Betriebssystem-Informationen ermitteln 
  OSVI.dwOSVersionInfoSize = Len(OSVI) 
  GetVersionEx OSVI 
  ' Liegt Windows 9x/Me vor? 
  If OSVI.dwPlatformId <> VER_PLATFORM_WIN32_NT Then 
    ' Windows 9x/Me: 
    ' Definition der Umgebungsvariablen in AUTOEXEC.BAT hinzufügen. 
    ' Die Umgebungsvariable wird systemweit erst nach Neustart des 
    ' Systems gültig. 
    On Error Resume Next 
    ff = FreeFile() 
    Open "c:\autoexec.bat" For Append As #ff 
      Print #ff, "SET " & VariableName & "=" & VariableValue 
    Close #ff 
    SetEnvironVar = (Err.Number = 0) 
    Exit Function 
  End If 
  ' Windows NT/2000/XP: Umgebungsvariable in die Registry schreiben 
  If Systemwide Then ' System-Umgebungsvariable 
    If RegWriteString(HKEY_LOCAL_MACHINE, _ 
                      "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", _ 
                      VariableName, _ 
                      VariableValue) = False Then 
      Exit Function ' Wert konnte nicht geschrieben werden 
    End If 
  Else ' Benutzer-Umgebungsvariable 
    If RegWriteString(HKEY_CURRENT_USER, _ 
                      "Environment", _ 
                      VariableName, _ 
                      VariableValue) = False Then 
      Exit Function ' Wert konnte nicht geschrieben werden 
    End If 
  End If 
  ' Änderung propagieren 
  PropagateChange "Environment" 
  ' Bei Erreichen dieser Zeile war das Setzen erfolgreich: 
  SetEnvironVar = True 
End Function 
Private Function RegWriteString(ByVal ToplevelKey As REGISTRYKEYS, _ 
                                ByVal SubKey As String, _ 
                                ByVal ValueName As String, _ 
                                ByVal Value As String _ 
                                ) As Boolean 
' Schreibt einen String in die Windows-Registrierungsdatenbank 
' (Registry). Ggf. notwendige Rechte werden vorausgesetzt. 
' ----------------------------------------------------------------- 
' Parameterinformationen: 
' ----------------------------------------------------------------- 
' ToplevelKey:  Hauptzweig der Registry, in den geschrieben werden 
'               soll. 
' SubKey:       Pfad unterhalb des Hauptzweiges, unter dem ein 
'               Stringwert abgelegt werden soll. 
' ValueName:    Name des Schlüssels, der erzeugt / überschrieben 
'               werden soll. 
' Value:        String, der als Wert des Schlüssels ValueName 
'               geschrieben werden soll. 
' Rückgabewert: TRUE bei Erfolg, FALSE bei Misserfolg. 
' ----------------------------------------------------------------- 
Dim RetVal As Long 
Dim hKey As Long 
Dim lngDisposition As Long 
  ' Einleitende Backslash-Angabe ggf. abschneiden 
  If Left$(SubKey, 1) = "\" And Len(SubKey) > 1 Then 
    SubKey = Mid$(SubKey, 2) 
  End If 
  ' Registry-Schlüssel öffnen 
  RetVal = RegCreateKeyEx(ToplevelKey, SubKey, _ 
                          0, vbNullString, _ 
                          REG_OPTION_NON_VOLATILE, _ 
                          KEY_CREATE_SUB_KEY Or KEY_SET_VALUE, _ 
                          0, hKey, lngDisposition) 
  If RetVal = ERROR_SUCCESS Then 
    ' Stringwert in diesem Schlüssel erzeugen / setzen 
    RetVal = RegSetValueEx(hKey, ValueName, 0, _ 
                           REG_SZ, ByVal Value, Len(Value)) 
    ' Bei Erfolg Funktionsrückgabewert True, andernfalls False 
    RegWriteString = (RetVal = ERROR_SUCCESS) 
  End If 
  ' Registry-Schlüssel schliessen 
  RegCloseKey hKey 
End Function 
Private Sub PropagateChange(Optional ByVal Area As String, _ 
                            Optional ByVal Timeout As Long = 5000&) 
' Propagiert eine Änderung durch Senden der Nachricht 
' WM_SETTINGCHANGE an alle Hauptfenster. 
' ----------------------------------------------------------------- 
' Parameterinformationen: 
' ----------------------------------------------------------------- 
' Area:    Beschreibung des Bereichs, in dem Änderungen vorgenommen 
'          wurden, über die informiert werden soll. 
' Timeout: Zeit in Millisekunden, die auf die Propagierung maximal 
'          verwendet werden soll. 
' ----------------------------------------------------------------- 
Dim lResult As Long 
  SendMessageTimeout HWND_BROADCAST, _ 
                     WM_SETTINGCHANGE, _ 
                     0, ByVal Area, _ 
                     SMTO_ABORTIFHUNG, _ 
                     Timeout, _ 
                     lResult 
End Sub