Buchempfehlung
Windows System Programming
Windows System Programming
Das Kompendium liefert viele interessante Informationen zur Windows-Programmierung auf Englisch. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Code-Beispiel

Code-Beispiele » System

Externes Programm starten und wieder beenden [Windows]

Lizenz:Erster Autor:Letzte Bearbeitung:
FBPSLAdministratorSebastian 01.11.2014

Der folgende Code demonstriert, wie sich unter Windows eine externe Anwendung zunächst aufrufen und anschließend wieder beenden lässt. Beim Beenden wird zunächst versucht, die Zielanwendung "sanft" zu beenden (entspricht einem Klick auf das [X] in der Titelleiste). Sind nicht gespeicherte Daten vorhanden, wird so eventuell ein Nachfragedialog wie "Möchten Sie die Änderungen vor dem Beenden speichern?" angezeigt. Nach einer bestimmten Wartezeit wird das Zielprogramm schließlich abgeschossen. Nicht gespeicherte Änderungen in dem Programm gehen dabei verloren.

Beachte folgende zwei Unzulänglichkeiten:

Links zu den verwendeten WinAPI-Funktionen und -Strukturen:

'
' BEISPIELPROGRAMM:
' Externes Programm unter Windows starten, seine ProcessID ermitteln
' und das Programm nach einer bestimmten Zeit automatisch wieder beenden
'
' Getestet mit Windows 7 Professional 64 Bit
'
' Compiliert mit FreeBASIC 0.23.0 stable fuer Windows
'
' Lizenz: FBPSL
'
' Datum: 06.06.2012   - FreeBASIC-Portal.de
'

#include "windows.bi"
#include "win\shellapi.bi"

#define TA_FAILED 0
#define TA_SUCCESS_CLEAN 1
#define TA_SUCCESS_KILL 2

' Funktionen zum Beenden einer Anwendung
Declare Function TerminateAppEnum (ByVal hwnd  As HWND,    ByVal lParam As LPARAM    ) As Integer
Declare Function TerminateApp     (ByVal dwPID As Integer, ByVal dwTimeout As Integer) As Integer

' Funktion zum Starten der Anwendung und Ermitteln der ProcessID
Declare Function startProgramAndGetPID (programToStart As String, parameters As String) As Integer


Type TERMINFO
    dwID As Integer
    dwThread As Integer
End Type

dim as string program = "notepad.exe"   'Beispielprogramm Windows-Editor Notepad.exe
dim as integer countdown = 10  'Programm fuer 10 Sekunden offen lassen und dann wieder beenden

dim as integer processID, closeResult


Print "Starte " & program & "..."

processID = startProgramAndGetPID (program, "")

If (processID = -1) Then
    Print "Fehler: Programm konnte nicht gestartet werden. Dateiname/Pfad korrekt?"
    Sleep: End 1
Else
    Print "Das Programm wurde gestartet. Die Prozess-ID ist " & processID & "."
End If

Print   'Leerzeile ausgeben
Print "In " & countdown & " Sekunden versuchen wir, das Programm wieder zu beenden..."
For i As Integer = countdown To 1 Step -1
    Print i; " ";
    Sleep 1000, 1
Next i
Print " [GO!]"

Print
Print "Beende das Programm..."

' Der Parameter 3000 bedeutet, dass wir dem Programm 3000ms (= 3 Sekunden) Zeit
' geben, sich freiwillig zu schliessen (entspricht einem Klick auf das [X] oben
' in der Fensterleiste). Nach Ablauf dieser Frist wird das Programm abgeschossen
' ("kill"), wenn es dann immer noch laeuft.
' Wichtig: Wird das Programm abgeschossen, gehen nicht gespeicherte Daten in dem
' Programm verloren.
closeResult = TerminateApp (processID, 3000)

Print

Select Case closeResult
Case TA_SUCCESS_CLEAN:
    Print "Erfolg: Das Programm wurde innerhalb der vorgegebenen Wartezeit"
    Print "        sanft beendet."
Case TA_SUCCESS_KILL:
    Print "Erfolg: Das Programm wurde nach Ablauf der vorgegebenen max. Wartezeit"
    Print "        abgeschossen. Nicht gespeicherte Daten in dem Programm gingen"
    Print "        eventuell verloren."
Case TA_FAILED:
    Print "Fehler: Das Programm konnte weder geschlossen noch abgeschossen werden."
End Select


Print
Print "Druecken Sie eine beliebige Taste zum Beenden."

sleep
end



' Diese Funktion wird NICHT durch den Benutzer aufgerufen, sondern nur intern verwendet!
Function TerminateAppEnum (ByVal hwnd As HWND, ByVal lParam As LPARAM) As Integer
      Dim As Integer dwID
      GetWindowThreadProcessId (hwnd, @dwID)
      if (dwID = Cast(LPARAM,lParam)) Then PostMessage(hwnd, WM_CLOSE, 0, 0)
      return TRUE
End Function


' Diese Funktion wird durch den Benutzer aufgerufen. Ihr wird die Prozess-ID des zu
' beendenden Programms uebergeben. Zunaechst wird fuer dwTimeout Sekundene lang probiert,
' das Programm "sanft" zu beenden. Klappt das nicht im vorgegebenen Zeitraum, wird der
' Zielprozess abgeschossen.
' Quelltext basiert auf C-Code-Beispiel: http://support.microsoft.com/kb/178893/en-us
Function TerminateApp (ByVal dwPID As Integer, ByVal dwTimeout As Integer) As Integer
    Dim hProc As HANDLE
    Dim dwRet As Integer

    ' Wenn Prozess nicht mit PROCESS_TERMINATE-Rechten geoeffnet werden
    ' kann, aufgeben und Funktion verlassen.
    hProc = OpenProcess (SYNCHRONIZE Or PROCESS_TERMINATE, FALSE, Cast(DWORD,dwPID))
    if (hProc = NULL) then return TA_FAILED

    ' Callback-Funktion TerminateAppEnum() fuer alle Fenster aufrufen, deren
    ' PID der uebergebenen dwPID entspricht. TerminateAppEnum() sendet dann
    ' an diese Fenster WM_CLOSE.
    EnumWindows (@TerminateAppEnum, dwPID)

    ' Fuer die in dwTimeout angegebene Zeit auf das Beenden warten. Wenn
    ' das nichts bringt, anschliessend versuchen, den Prozess abzuschiessen
    ' mit TerminateProcess ("Kill").
    if (WaitForSingleObject(hProc, dwTimeout) <> WAIT_OBJECT_0) Then
        if (TerminateProcess(hProc,0)) Then
            dwRet = TA_SUCCESS_KILL
        else
            dwRet = TA_FAILED
        end if
    else
        dwRet = TA_SUCCESS_CLEAN
    end if

    CloseHandle (hProc)

    ' Statuscode zurueckgeben an Aufrufer:
    '  - TA_FAILED - wenn das Beenden fehlgeschlagen ist
    '  - TA_SUCCESS_CLEAN - wenn der Prozess sauber ueber WM_CLOSE beendet wurde
    '  - TA_SUCCESS_KILL - wenn der Prozess mit TerminateProcess() abgeschossen wurde
    return dwRet
End Function


' Startet ein Programm (optional mit Parametern) und gibt seine PID zurueck.
' Im Fehlerfall wird -1 zurueckgegeben.
Function startProgramAndGetPID (programToStart As String, parameters As String) As Integer
    Dim result As BOOL
    ' Siehe: SHELLEXECUTEINFO - http://msdn.microsoft.com/en-us/library/bb759784.aspx
    Dim seInfo As SHELLEXECUTEINFO
    Dim workingDir As String = EXEPATH  'Arbeitsverzeichnis standardmaessig auf das Verzeichnis
                                        'festlegen, in dem die EXE-Datei hier liegt.
    With seInfo
        .cbSize = SizeOf(SHELLEXECUTEINFO)
        .fMask = SEE_MASK_NOCLOSEPROCESS
        .hWnd = 0
        .lpVerb = StrPtr("open")
        .lpFile = StrPtr(programToStart)
        .lpParameters = StrPtr(parameters)
        .lpDirectory = StrPtr(workingDir)
        .nShow = SW_SHOWNORMAL  ' Siehe: http://msdn.microsoft.com/en-us/library/bb762153.aspx
    End With
    ' Siehe: ShellExecuteEx - http://msdn.microsoft.com/en-us/library/bb762154.aspx
    result = ShellExecuteEx (@seInfo)
    If (result = 0) Then
        Return -1  'Fehler
    Else
        Dim As Integer processID = GetProcessID(seInfo.hProcess)
        Return processID
    End if
End Function

Zusätzliche Informationen und Funktionen
  • Das Code-Beispiel wurde am 06.06.2012 von AdministratorSebastian angelegt.
  • Die aktuellste Version wurde am 01.11.2014 von Mitgliedgrimlax gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen