• Sub-Prozeduren und Function-Prozeduren - B E I S P I E L E
Sub-Prozeduren und Function-Prozeduren - eine Einführung
In der Literatur wird der Einfachheit halber häufig von Funktionen (für Function-Prozeduren) und Prozeduren (für Sub-Prozeduren) gesprochen.
Interne Function-Prozeduren sind für viele Aufgaben bereits reichlich in WSH / VBScript enthalten. Ihre Ergebnisse werden häufig an Variablen zur weiteren Verarbeitung übergeben: xx = now(). Die Variable xx enthält nach diesem Funktionsaufruf die aktuelle Zeit mit Datum und Uhrzeit.
Eigene Funktionen und Prozeduren werden für gewöhnlich an das Ende eines Skripts geschrieben, wodurch sich die Übersichtlichkeit erhöht.
Im folgenden eine Übersicht, wie Prozeduren aufzurufen sind bzw. welche Unterschiede zwischen Sub-Prozeduren und Function-Prozeduren bestehen.
Prinzipiell muss (aus Prozedur-Sicht) zwischen 'internen Variablen' und 'externen Variablen' unterschiedenen werden:
• interne Variablen werden immer innerhalb der Prozedur mit Dim ... - oder Const ... -Anweisungen definiert. Damit 'lebt' die Variable und deren Inhalt nur innerhalb der Prozedur - weder der Inhalt noch der Variable-Name ist außerhalb der Prozedur bekannt oder verwendbar. Umgekehrt ist eine (globale) Variable, die außerhalb einer Prozedur mit dem selben Variablen-Namen definiert wurde, nie innerhalb der Prozedur verfügbar.
• externe Variablen oder genauer globale Variablen werden außerhalb der (bzw. aller) Prozeduren mit Dim ... - oder Const ... -Anweisungen definiert. Dadurch 'lebt' die Variable und deren Inhalt innerhalb des gesamten Skripts und damit auch in allen Prozeduren - es sei denn, in einer Prozedur wird eine Variable mit dem selben Namen definiert. Dadurch ist für die Prozedur (intern) die globale Variable (und deren Inhalt) 'überschrieben'.
Sind die (internen) Variablen konsequent mit Dim ... - oder Const ... -Anweisungen deklariert, kommt es zu keinen (Variablen-) Konflikten und das Skript ist etwas schneller (so stehts in der VBScript-Hilfe). Außerdem können die Funktionen von anderen Programmierern verwendet werden, ohne dass sie sie verstehen müssen - solange das Ergebnis den Erwartungen entspricht ;-)
↑ Zum Seitenanfang ↑
Function-Prozedur | Sub - Prozedur |
---|---|
(Funktion) | (Prozedur) |
Option Explicit Dim a, k, z k = 10 z = 9 a = Summe (k, 20) MsgBox Summe (a, 5) ' ergibt 35 MsgBox z Function Summe (i, x) Dim z z = 5 Summe = i + x End Function ' Summe |
Option Explicit Dim yx, z, k k = 10 z = 9 Addition k, 20 MsgBox yx ' ergibt 30 MsgBox z Sub Addition (a, c) ' Dim yx Dim z z = 5 yx = a + c End Sub ' Addition |
Die Aufrufparameter werden in Klammern gesetzt:
Summe (k, 20). |
Die Aufrufparameter werden nicht in Klammern notiert:
Addition k, 20. |
Function FuncName (u, v) bzw. Sub SubName (u, v) erwartet beim Aufruf immer! zwei Werte. | |
Fehlt Dim z inerhalb der Prozedur, wird z = 5 nach 'außen' gegeben und MsgBox z zeigt die Zahl 5. | |
Mit Dim yx inerhalb der Prozedur ist MsgBox yx leer. | |
Rückgabewert: Wird innerhalb der Prozedur einer Variable, die den selben Namen wie die Prozedur selbst hat, ein Wert zugewiesen (summe=...), wird auch ein Wert nach außen übergeben (xy=summe(...) ). |
Rückgabewert: Innerhalb der Prozedur muss eine (Ziel-) Variable, die
außerhalb der Prozedur verwendet oder definiert
wurde,
einen Wert erhalten. |
Exit Function beendet die Prozedur-Abarbeitung vorzeitig. | Exit Sub beendet die Prozedur-Abarbeitung vorzeitig. |
Function-Prozeduren sind überschreibbar: Function now(u, v) erwartet jetzt zwei Parameter und liefert nicht mehr Datum und Uhrzeit! |
Sub-Prozeduren sind nicht überschreibbar: Sub now(u, v) führt zu einer Fehlermeldung! |
Dim ... -Anweisungen verhindern Konflikte mit Variablen außerhalb der Prozeduren. | |
Option Explicit erleichtert die Fehlersuche. |
↑ Zum Seitenanfang ↑
Ein 'richtiges' Beispiel verdeutlicht den unkomplizierten Einsatz:
Sollen wiederholt Zwischenergebnisse in eine Datei protokolliert werden, bietet sich eine Prozedur an. Immer wenn es etwas wichtiges für die Protokolldatei gibt, fügt man den Prozedur-Aufruf LogDatei "Meldung" ein und die Prozedur erweitert dann die Protokolldatei:
Sub LogDatei (TextX)
Dim fso, FileOut
Set fso = CreateObject("Scripting.FileSystemObject")
Set FileOut = fso.OpenTextFile (WScript.ScriptName & ".Log", 8, true)
FileOut.WriteLine (TextX)
FileOut.Close
Set FileOut = Nothing
Set fso = Nothing
End Sub ' LogDatei
Die Prozedur öffnet mit den Zeilen 3 und 4 eine Datei, deren Name sich
aus dem Skriptnamen
und '.log' zusammensetzt. Die LogDatei von test.vbs wird also
test.vbs.log heißen.
Man erkennt dadurch sofort, von welchem Skript die Logdatei erstellt wurde.
(Die Zahl 8 in Zeile 4 sorgt dafür, dass die Logdatei erweitert wird
und 'true' dafür, dass die Datei neu angelegt wird, fals es sie noch nicht gibt.)
Zeile 5 schreibt die an die Funktion übergebenen Informationen in die
Protokolldatei.
Dim fso, FileOut
Set fso = CreateObject("Scripting.FileSystemObject")
Set FileOut = fso.OpenTextFile (WScript.ScriptName & ".Log", 8, true)
FileOut.WriteLine (TextX)
FileOut.Close
Set FileOut = Nothing
Set fso = Nothing
End Sub ' LogDatei
Folgende Zeilen erstellen bzw. erweitern eine Protokolldatei durch Aufrufe der Prozedur LogDatei:
LogDatei vbCRLF
LogDatei now()
xz = "Sag mal BESCHEID!"
MsgBox xz
LogDatei xz
Nachdem eine Leerzeile mit vbCRLF und Datum und Zeit mit now()
ins Protokoll geschrieben wurde, werden die eigentlichen Informationen protokolliert.
Man kann auch einige Zeilen zusammen fassen:
LogDatei now()
xz = "Sag mal BESCHEID!"
MsgBox xz
LogDatei xz
xz = vbCRLF & vbCRLF & now() & vbCRLF & "Sag mal BESCHEID!"
MsgBox xz
LogDatei xz
MsgBox xz
LogDatei xz
Mit Prozeduren und Funktionen (also Sub- und Function-Prozeduren) lassen sich einmal als gut befundene Zeilen sehr einfach immer wieder und überall in vielen neuen und alten Skripten verwenden (Ein toller Satz!).
↑ Zum Seitenanfang ↑
Sub-Prozeduren und Function-Prozeduren - B E I S P I E L E
Bubblesort
Diese Funktion ist Teil des Skripts Sort-BubbleSort.vbs, in dem beim zeilenweisen Lesen einer Datei die Zeilen in ein Array übergeben werden. Mit der folgenden Function wird das Array nach dem Bubblesort-Verfahren sortiert. Die Funktion kann mit Array = bubblesort(Array) aufgerufen werden. Array enthält danach die selben Werte, die jetzt aber alphabetisch sortiert sind.
'**************************************************************
Function bubblesort(arrSortieren) ' v3.1 - http://dieseyer.de
'**************************************************************
Dim i, j
for i = 0 to ubound(arrSortieren)
for j = i + 1 to ubound(arrSortieren)
if UCase( arrSortieren(i) ) > UCase( arrSortieren(j) ) then
bubblesort = arrSortieren(i)
arrSortieren(i) = arrSortieren(j)
arrSortieren(j) = bubblesort
end if
next
next
End Function ' bubblesort() ' v3.1 - http://dieseyer.de
'**************************************************************
Function bubblesort(arrSortieren) ' v3.1 - http://dieseyer.de
'**************************************************************
Dim i, j
for i = 0 to ubound(arrSortieren)
for j = i + 1 to ubound(arrSortieren)
if UCase( arrSortieren(i) ) > UCase( arrSortieren(j) ) then
bubblesort = arrSortieren(i)
arrSortieren(i) = arrSortieren(j)
arrSortieren(j) = bubblesort
end if
next
next
End Function ' bubblesort() ' v3.1 - http://dieseyer.de
'**************************************************************
↑ Zum Seitenanfang ↑
Erstellen bzw. Erweitern einer Protokolldatei
LogDatei "Es ist jetzt " & now() erweitert eine Logdatei, die den selben Namen wie das aufrufende Skript hat (aber mit der Endung .log).
'**************************************************************
Sub LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
Dim fso, File, FileOut
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
' File = fso.GetBaseName( WScript.ScriptName ) & ".log"
File = WScript.ScriptName & ".log"
Set FileOut = fso.OpenTextFile( File , 8, true)
' FileOut.WriteLine (vbCRLF & Now() )
FileOut.WriteLine (LogTxt)
FileOut.Close
Set FileOut = Nothing
Set fso = Nothing
End Sub ' LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
Sub LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
Dim fso, File, FileOut
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
' File = fso.GetBaseName( WScript.ScriptName ) & ".log"
File = WScript.ScriptName & ".log"
Set FileOut = fso.OpenTextFile( File , 8, true)
' FileOut.WriteLine (vbCRLF & Now() )
FileOut.WriteLine (LogTxt)
FileOut.Close
Set FileOut = Nothing
Set fso = Nothing
End Sub ' LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
Oder ganz kurz in einer einzigen Zeile:
'**************************************************************
Sub LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
WScript.CreateObject("Scripting.FileSystemObject").OpenTextFile(WScript.ScriptName & ".log", 8, true).WriteLine (LogTxt)
End Sub ' LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
Sub LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
WScript.CreateObject("Scripting.FileSystemObject").OpenTextFile(WScript.ScriptName & ".log", 8, true).WriteLine (LogTxt)
End Sub ' LogDatei (LogTxt) ' v3.9 - http://dieseyer.de
'**************************************************************
↑ Zum Seitenanfang ↑
Anzeigen der Protokolldatei (mit Notepad)
'**************************************************************
Sub LogDateiAnzeige ' v3.9 - http://dieseyer.de
'**************************************************************
WScript.CreateObject("WScript.Shell").run "notepad " & WScript.ScriptName ) & ".log"
End Sub ' LogDateiAnzeige ' v3.9 - http://dieseyer.de
'**************************************************************
Sub LogDateiAnzeige ' v3.9 - http://dieseyer.de
'**************************************************************
WScript.CreateObject("WScript.Shell").run "notepad " & WScript.ScriptName ) & ".log"
End Sub ' LogDateiAnzeige ' v3.9 - http://dieseyer.de
'**************************************************************
Ping-Anzeige auswerten
Ping wird aufgerufen und die Anzeige in eine Datei umgeleitet, um diese anschließend auszuwerten.
MsgBox PingTest ( "PCname" ) zeigt, ob der PC auf PING geantwortet hat.
'**************************************************************
Function PingTest ( IPtst ) ' v2.C - http://dieseyer.de
'**************************************************************
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
File = fso.GetBaseName( WScript.ScriptName ) & ".log"
WshShell.run ("%comspec% /c Ping " & IPtst & " -n 1 -w 500 > " & File ),0,true
' PING nur einmal ausführen => nur eine Zeile mit TTL=
Set FileIn = fso.OpenTextFile(File , 1, true)
' Datei zum Lesen öffnen
PingTest = "keine Antwort"
Do While Not (FileIn.atEndOfStream)
' wenn Datei nicht zu Ende ist, weiter machen
if InStr( CStr( FileIn.Readline ), "TTL=") > 1 then PingTest = "Antwort erhalten"
' eine Zeile lesen und auf Inhalt testen
Loop
FileIn.Close
Set FileIn = nothing
End Function ' PingTest ( IPtst ) ' v2.C - http://dieseyer.de
'**************************************************************
Function PingTest ( IPtst ) ' v2.C - http://dieseyer.de
'**************************************************************
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
File = fso.GetBaseName( WScript.ScriptName ) & ".log"
WshShell.run ("%comspec% /c Ping " & IPtst & " -n 1 -w 500 > " & File ),0,true
' PING nur einmal ausführen => nur eine Zeile mit TTL=
Set FileIn = fso.OpenTextFile(File , 1, true)
' Datei zum Lesen öffnen
PingTest = "keine Antwort"
Do While Not (FileIn.atEndOfStream)
' wenn Datei nicht zu Ende ist, weiter machen
if InStr( CStr( FileIn.Readline ), "TTL=") > 1 then PingTest = "Antwort erhalten"
' eine Zeile lesen und auf Inhalt testen
Loop
FileIn.Close
Set FileIn = nothing
End Function ' PingTest ( IPtst ) ' v2.C - http://dieseyer.de
'**************************************************************
↑ Zum Seitenanfang ↑
Netzkonfiguration auswerten bzw. Default GateWay ermitteln
Die Netzwerkkonfiguration wird unter Win9x/ME mit winipcfg und unter WinNT/2k/XP mit ipconfig /all angezeigt. Die Auswertung erfolgt ähnlich wie bei 'Ping-Anzeige auswerten'.
MsgBox DefaultGW () zeigt die ermittelte GateWay-IP-Adresse des PC's an, auf dem das Skript gestartet wurde.
'**************************************************************
Function DefaultGW ' v2.C - http://dieseyer.de
'**************************************************************
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set Env = WSHShell.Environment("PROCESS")
File = "winipcfg.out"
if Env("OS") = "Windows_NT" then
WSHShell.run "%comspec% /c ipconfig > " & Ziel, 0, True
' ipconfig nach Ziel umleiten
else
WSHShell.run "winipcfg /batch" ,0 ,True
' winipcfg /batch legt autom. "winipcfg.out" an
end if
Set FileIn = fso.OpenTextFile(File , 1, true)
' Datei zum Lesen öffnen
DefaultGW = ""
Do While Not (FileIn.atEndOfStream)
' wenn Datei nicht zu Ende ist, weiter machen
TextX = CStr( UCase( FileIn.Readline ) )
' eine Zeile lesen
if InStr( TextX , "GATEWAY") > 1 then
' auf Inhalt testen
DefaultGW = Mid( TextX, InStr(UCase( TextX ), ": ") + 1)
DefaultGW = trim(DefaultGW)
End if
Loop
FileIn.Close
Set FileIn = nothing
End Function DefaultGW ' v2.C - http://dieseyer.de
'**************************************************************
Function DefaultGW ' v2.C - http://dieseyer.de
'**************************************************************
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set Env = WSHShell.Environment("PROCESS")
File = "winipcfg.out"
if Env("OS") = "Windows_NT" then
WSHShell.run "%comspec% /c ipconfig > " & Ziel, 0, True
' ipconfig nach Ziel umleiten
else
WSHShell.run "winipcfg /batch" ,0 ,True
' winipcfg /batch legt autom. "winipcfg.out" an
end if
Set FileIn = fso.OpenTextFile(File , 1, true)
' Datei zum Lesen öffnen
DefaultGW = ""
Do While Not (FileIn.atEndOfStream)
' wenn Datei nicht zu Ende ist, weiter machen
TextX = CStr( UCase( FileIn.Readline ) )
' eine Zeile lesen
if InStr( TextX , "GATEWAY") > 1 then
' auf Inhalt testen
DefaultGW = Mid( TextX, InStr(UCase( TextX ), ": ") + 1)
DefaultGW = trim(DefaultGW)
End if
Loop
FileIn.Close
Set FileIn = nothing
End Function DefaultGW ' v2.C - http://dieseyer.de
'**************************************************************
↑ Zum Seitenanfang ↑
Verlaufs- bzw. Fortschrittanzeige beim Kopieren
Diese Prozedur geht auf eine Antwort auf eine MS-NG -Anfrage bzw. auf die Antwort von Ch. Basedau zurück. Da laut MS dafür die shell32.dll die Version 4.71 ( QuellCode> SHELL32DLLversion.VBS) oder später haben muss, wird das Kopieren in ein Prozedur verpackt, die dann entscheidet, welche der beiden Kopieroperation ausgeführt wird. Die Fortschrittanzeige wird nur angezeigt, wenn auch genügend Daten kopiert werden sollen Aufgerufen wird Prozedur mit ShellFolderCopy QuellVerz, ZielVerz
'**************************************************************
Sub ShellFolderCopy (Quelle, Ziel) ' v2.C - http://dieseyer.de
'**************************************************************
Dim WSHShell : Set WSHShell = WScript.CreateObject("WScript.Shell")
Dim fso : Set fso = WScript.CreateObject("Scripting.FileSystemObject")
' Betriebssystem ermitteln ( WinNT/2k/XP oder Win9x/ME )
Text = "\system32"
If not "Windows_NT" = WScript.CreateObject("WScript.Shell").Environment("Process")("OS") then
Text = "\system"
End If
Text = WSHShell.ExpandEnvironmentStrings("%WinDir%") & Text & "\shell32.dll"
Text = fso.GetFileVersion( text ) ' Versionsinfo (der Shell32.dll) holen
Text = Left ( CDbl ( text ), 3 ) ' Versionsinfo formatieren
If Text < 471 then
fso.CopyFolder Quelle, Ziel, True
Else
if not fso.FolderExists( Ziel ) then fso.CreateFolder( Ziel )
Set ShellApp = CreateObject("Shell.Application")
Set oZielOrdner = ShellApp.NameSpace( Ziel )
oZielOrdner.CopyHere Quelle , 16 'vOptions
Set ShellApp = nothing ' weil es nicht mehr gebraucht wird
Set oZielOrdner = nothing
End If
Set WSHShell = nothing
Set fso = nothing
End Sub ' ShellFolderCopy () ' v2.C - http://dieseyer.de
'**************************************************************
Sub ShellFolderCopy (Quelle, Ziel) ' v2.C - http://dieseyer.de
'**************************************************************
Dim WSHShell : Set WSHShell = WScript.CreateObject("WScript.Shell")
Dim fso : Set fso = WScript.CreateObject("Scripting.FileSystemObject")
' Betriebssystem ermitteln ( WinNT/2k/XP oder Win9x/ME )
Text = "\system32"
If not "Windows_NT" = WScript.CreateObject("WScript.Shell").Environment("Process")("OS") then
Text = "\system"
End If
Text = WSHShell.ExpandEnvironmentStrings("%WinDir%") & Text & "\shell32.dll"
Text = fso.GetFileVersion( text ) ' Versionsinfo (der Shell32.dll) holen
Text = Left ( CDbl ( text ), 3 ) ' Versionsinfo formatieren
If Text < 471 then
fso.CopyFolder Quelle, Ziel, True
Else
if not fso.FolderExists( Ziel ) then fso.CreateFolder( Ziel )
Set ShellApp = CreateObject("Shell.Application")
Set oZielOrdner = ShellApp.NameSpace( Ziel )
oZielOrdner.CopyHere Quelle , 16 'vOptions
Set ShellApp = nothing ' weil es nicht mehr gebraucht wird
Set oZielOrdner = nothing
End If
Set WSHShell = nothing
Set fso = nothing
End Sub ' ShellFolderCopy () ' v2.C - http://dieseyer.de
'**************************************************************