ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 30.10.2001

Diese Seite wurde zuletzt aktualisiert am 30.10.2001
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Starten und warten

Zurück...


Anzeige

(-hg) mailto:hg_shell@aboutvb.de

Die Shell-Funktion in Visual Basic ermöglicht leider nur eine asynchrone Ausführung einer über sie aufgerufenen weiteren Anwendung. Das bedeutet, dass Ihre Anwendung nicht auf eine Beendigung der aufgerufenen Anwendung wartet und somit der dem Aufruf nachfolgende Code sofort weiter ausgeführt wird. Bei einer synchronen Ausführung würde der Funktionsaufruf hingegen erst dann zurückkehren, wenn die aufgerufene Anwendung wieder (auf welche Weise auch immer) beendet worden ist.

Eine einfache Lösung der Aufgabe beruht weiterhin auf dem Aufruf der Shell-Funktion. Nun wird allerdings eine Schleife nachgeschaltet, die erst dann verlassen wird, wenn die aufgerufene Anwendung tatsächlich wieder beendet worden ist. Um dies festzustellen, müssen wir den Prozess der aufgerufenen Anwendung befragen. Auch hier ist ein einfacher Weg, den Prozess nach seinem Exit-Code zu befragen. So lange der Prozess noch aktiv ist, entspricht sein Exit-Code dem Konstant-Wert STILL_ACTIVE. Wenn der Prozess beendet wird, ist der Exit-Code im Normalfall 0 - es sei denn die beendete Anwendung hätte selbst explizit einen bestimmten Exit-Code gesetzt (beispielsweise siehe: "Rückgabewert an Stapeldatei" - wobei ein Error-Code und ein Exit-Code ein und dasselbe sind).

Den zu befragenden Prozess öffnen wir anhand der von der Shell-Funktion zurückgegebenen Task-Id mit der API-Funktion OpenProcess im Modus PROCESS_QUERY_INFORMATION. In der besagten Schleife rufen wir den aktuellen Status des Exit-Codes über die API-Funktion GetExitCodeProcess ab. Ändert sich der Exit-Code, wird die Schleife verlassen. Nun entsorgen wir noch das Prozess-Handle mittels der API-Funktion CloseHandle.

Packen Sie das Ganze in eine Funktion, entspricht der Aufruf dem der gewohnten Shell-Funktion. Als kleinen nützlichen und informativen Nebeneffekt können Sie hier sogar noch den Exit-Code als Rückgabewert der Funktion verwerten.

Private Declare Function CloseHandle Lib "kernel32" _
 (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" _
 (ByVal hProcess As Long, ExitCode As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" _
 (ByVal DesiredAccess As Long, ByVal InheritHandle As Long, _
 ByVal ProcessId As Long) As Long

Public Function ShellWait(Exec As String, _
 Optional WindowStyle As VbAppWinStyle = vbMinimizedFocus) _
 As Long

  Dim nTaskId As Long
  Dim nHProcess As Long
  Dim nExitCode As Long
  
  Const STILL_ACTIVE = &H103
  Const PROCESS_QUERY_INFORMATION = &H400
    
  nTaskId = Shell(Exec, WindowStyle)
  nHProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, nTaskId)
  Do
    DoEvents
    GetExitCodeProcess nHProcess, nExitCode
  Loop While nExitCode = STILL_ACTIVE
  CloseHandle nHProcess
  ShellWait = nExitCode
End Function

Bei der eigentlich beabsichtigten synchronen Ausführung ist die Gewinnung des Exit-Codes eher nur ein Abfallprodukt. Wenn Sie hingegen die Shell-Funktion wie gewohnt asynchron aufrufen, aber trotzdem über das Beenden der aufgerufenen Anwendung informiert werden möchten, Müssen Sie den Shell-Aufruf und die Überwachungsschleife entkoppeln. Den Exit-Code gewinnen Sie auch hier wieder als Abfallprodukt.

Die Entkopplung erfolgt über einen Timer, der auf einem ansonsten unsichtbar bleibenden Form platziert ist, während die Information über die Beendigung der aufgerufenen Anwendung über ein Ereignis (ShellExit) erfolgt. Wie in der oben stehenden Funktion werden die Shell-Funktion zum Start der gewünschten Anwendung aufgerufen und das Prozess-Handle ermittelt. Anschließend wird jedoch der Timer aktiviert und der Aufruf der hier als Shell-Methode des besagten Forms angelegten Aufruf-Prozedur kehrt unmittelbar danach, also asynchron, zurück. Die Task-Id und das Prozess-Handle werden in privaten Variablen des Forms abgelegt und können über Eigenschaften-Prozeduren zwischendurch abgefragt werden. Die Aufruf-Methode gibt die TaskId zurück, anhand derer später auch eine eindeutige Zuordnung des ShellExit-Ereignisses erfolgen kann.

Private Declare Function CloseHandle Lib "kernel32" _
 (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" _
 (ByVal HProcess As Long, ExitCode As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" _
 (ByVal DesiredAccess As Long, ByVal InheritHandle As Long, _
 ByVal ProcessId As Long) As Long

Public Event ShellExit(ByVal TaskId As Long, _
 ByVal ExitCode As Long)

Private pTaskId As Long
Private pHProcess As Long
Private pExitCode As Long

Public Function Shell(Exec As String, _
 Optional WindowStyle As VbAppWinStyle = vbMinimizedFocus) _
 As Long

  Const PROCESS_QUERY_INFORMATION = &H400
  
  pTaskId = VBA.Shell(Exec, WindowStyle)
  pHProcess = _
   OpenProcess(PROCESS_QUERY_INFORMATION, False, pTaskId)
  Shell = pTaskId
  tmr.Enabled = True
End Function

Public Property Get TaskId() As Long
  TaskId = pTaskId
End Property

Public Property Get hProcess() As Long
  hProcess = pHProcess
End Property

Der Eintritt in die Überwachungsschleife erfolgt im Timer-Ereignis des Timers. Dort deaktiviert sich zunächst der Timer selbst und entlädt das Form (das ja durch die Aktivierung des Timers unweigerlich geladen worden ist). Wenn die nachfolgende Schleife verlassen wird, wird das ShellExit-Ereignis ausgelöst, das als Parameter die Task-Id und den Exit-Code mitnimmt.

Private Sub tmr_Timer()
  Const STILL_ACTIVE = &H103
    
  tmr.Enabled = False
  Unload Me
  Do
    DoEvents
    GetExitCodeProcess pHProcess, pExitCode
  Loop While pExitCode = STILL_ACTIVE
  CloseHandle pHProcess
  pHProcess = 0
  RaiseEvent ShellExit(pTaskId, pExitCode)
End Sub

Der Aufruf einer Anwendung und die Auswertung ihrer Beendigung über ein solches Entkoppelungsform (frmShell) könnte zum Beispiel so aussehen

Private WithEvents eShell As frmShell

Private Sub Command1_Click()
  Set eShell = New frmShell
  eShell.Shell "calc.exe", vbNormalFocus
  MsgBox "Rechner 2 geöffnet"
End Sub

Private Sub eShell_ShellExit(ByVal hTask As Long, _
 ByVal ExitCode As Long)

  MsgBox "Rechner 2 geschlossen"
  Set eShell = Nothing
End Sub

Beispiel-Projekt und Module zu Shell (shell.zip - ca. 4,1 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer