Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / System / Shell / Sync

Programm starten, warten, ExitCode bestimmen

Historie
19.12.2002Rückgabewert als Long definiert; Hinweis für VBA-Nutzer
29.10.2001Funktion liefert nun den ExitCode des aufgerufenen Programms zurück
30.11.2000Hinweis bzgl. Ausführung von DOS-Befehlen hinzugefügt
14.10.2000Beispiel hinzugefügt
??.??.1999Erste Version; mit Unterstützung von Mathias Schiffer

Einleitung

Oft muß ein externes Programm gestartet werden (z.B. eine Batch) und auf Beendigung desselben gewartet werden, um beispielsweise auf Rückgabeergebnisse (in Form von erzeugten Dateien) zugreifen zu können.

Die VB-Funktion Shell bietet diese Möglichkeit leider nicht standardmäßig, d.h. die Programmausführung in VB wird fortgesetzt, sobald das externe Programm gestartet wurde.

Glücklicherweise kann durch API-Einsatz eine Synchronisierung erzwungen werden. Die unten gezeigte Routine erweitert die Shell-Funktion von VB u.a. um einen optionalen Parameter Events, welcher angibt, ob die VB-Anwendung auf Events reagieren soll (Voreinstellung) oder nicht (die "Vater"-Anwendung reagiert dann nicht mehr).

Beispiele

Allgemein

Das folgende Beispiel startet (bei Klick auf die Form) den Texteditor von Windows und wartet auf seine Beendigung. Erst wenn Notepad beendet wurde, geht die Programmausführung weiter: Es piept kurz, bevor das Formular sich entlädt.

Private Sub Form_Click()
  ShellX "notepad.exe", vbNormalFocus
  Beep '  :-)
  Unload Me
End Sub
ExitCode

Die ShellX-Funktion liefert den ExitCode eines Programms zurück. Oft enthält dieser einen Wert ungleich Null, falls ein Fehler aufgetreten ist. Dies kann z.B. mit dem in "Programm mit ErrorLevel beenden" gezeigten Verfahren dazu benutzt werden, kleine Informationen (genauer: eine Ganzzahl) an das aufrufende Programm zu übergeben:

n = ShellX("D:\Test\BigCalc.exe 27319 98765")
MsgBox "Ergebnis: " & n
DOS-Kommando

Soll ein DOS-interner Befehl wie z.B. dir ausgeführt werden, so muss der Kommandozeilen-Interpreter mit dem Schalter "/c" aufgerufen werden:

Private Sub Form_Click()
  Dim sCmd As String
  Dim sShell As String

  sCmd = "dir > C:\Data\Test.tmp"
  sShell = Environ$("COMSPEC")

  ShellX sShell & " /c " & sCmd, vbHide
End Sub

Code / Quelltext

Im Deklarationsteil eines Moduls müssen folgende API-Funktionen bekanntgemacht werden:

Private Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" ( _
    ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" ( _
    ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
    ByVal dwProcessId As Long) As Long

Die eigentliche Funktion erwartet (wie die VB-Funktion Shell) den Pfad zur Anwendung sowie (optional) den Fensterstil. Mit Shell wird die Anwendung wie gewünscht gestartet. Die Process-ID wird in ein Process-Handle transformiert, womit dann solange GetExitCodeProcess aufgerufen wird, bis der ExitCode nicht mehr STILL_ACTIVE ist, d.h. die Anwendung beendet wurde:

' ©2002 by Jost Schwider, http://vb-tec.de/
Public Function ShellX( _
    ByVal PathName As String, _
    Optional ByVal WindowStyle As VbAppWinStyle = vbMinimizedFocus, _
    Optional ByVal Events As Boolean = True _
  ) As Long

  'Deklarationen:
  Const STILL_ACTIVE = &H103&
  Const PROCESS_QUERY_INFORMATION = &H400&
  Dim ProcId As Long
  Dim ProcHnd As Long

  'Prozess-Handle holen:
  ProcId = Shell(PathName, WindowStyle)
  ProcHnd = OpenProcess(PROCESS_QUERY_INFORMATION, True, ProcId)

  'Auf Prozess-Ende warten:
  Do
    If Events Then DoEvents
    GetExitCodeProcess ProcHnd, ShellX
  Loop While ShellX = STILL_ACTIVE

  'Aufräumen:
  CloseHandle ProcHnd

End Function

Tipp: Unter Office (VBA) sind die VB-Enumerationen (hier: VbAppWinStyle) nicht bekannt. Da diese intern als Long betrachtet werden, kann man die obige Deklaration (z.B. in Excel oder Word) auch so schreiben:

' ©2002 by Jost Schwider, http://vb-tec.de/
Public Function ShellX( _
    ByVal PathName As String, _
    Optional ByVal WindowStyle As Long = vbMinimizedFocus, _
    Optional ByVal Events As Boolean = True _
  ) As Long

© Jost Schwider, 30.04.2000-20.12.2002 - http://vb-tec.de/xshell.htm