Startseite

© Juni 2015 • by dieseyer • all rights reserved • www.dieseyer.de

Du bist hier: dieseyer.de > VBS-Skripte > Sub / Function
Sub / Function
• Sub-Prozeduren und Function-Prozeduren - eine Einführung

• 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.  

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:
xz = vbCRLF & vbCRLF & now() & vbCRLF & "Sag mal BESCHEID!"
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
'**************************************************************


↑ 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
'**************************************************************

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
'**************************************************************


↑ 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
'**************************************************************

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
'**************************************************************


↑ 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
'**************************************************************


↑ 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
'**************************************************************


↑ Zum Seitenanfang ↑