![]() |
ShellExecuteEx + TerminateProcess
Hallo,
ich verwende ShellExecuteEx um eine Konsole zu starten, die einen Befehl ausführt und die Ausgabe in eine Textdatei umleitet soll. Da der Befehl kontinuierlich Daten erzeugt, möchte ich ihn irgendwann abbrechen. Dafür sollte doch TerminateProcess geeignet sein. Das Problem ist, das Beenden funktioniert nicht. Für das Bespiel hier habe ich einfach ping verwendet und die Umleitung weggelassen, da sie für das eigentliche Problem nicht wichtig ist. Ich habe also eine Form mit zwei Buttons und den folgenden Funktionen erstellt:
Delphi-Quellcode:
Das Flag
procedure TForm1.Button1Click(Sender: TObject);
begin ShExecInfo.cbSize := SizeOf(ShellExecuteInfo); ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := 'cmd.exe'; ShExecInfo.lpParameters := '/c ping -t delphipraxis.net'; ShExecInfo.nShow := SW_SHOW; if not ShellExecuteEx(@ShExecInfo) then raise Exception.Create('ShellExecuteEx error = ' + IntToStr(GetLastError)); end; procedure TForm1.Button2Click(Sender: TObject); begin if not TerminateProcess(ShExecInfo.hProcess, 0) then raise Exception.Create('TerminateProcess error = ' + IntToStr(GetLastError)); end;
Delphi-Quellcode:
führt dazu, dass das Process handle in der Variablen
SEE_MASK_NOCLOSEPROCESS
Delphi-Quellcode:
gespeichert wird. Es gibt keinerlei Fehlermeldung, aber der Prozess wird nicht beendet. Was mache ich falsch? Gibt es eine andere Möglichkeit die Konsole zu schließen?
ShExecInfo.hProcess
PS: CreateProcess verwende ich nicht, da dort die Umleiten der Ausgabe in eine Datei nicht funktioniert. |
AW: ShellExecuteEx + TerminateProcess
Der Doku "
![]() Zitat:
![]() Wenn ich das allerdings anmerken darf, das ganze erscheint trotzdem etwas Quick & Dirty. Bist du sicher, dass beispielsweise der Umweg über Dateien auf der Festplatte notwendig ist? Das tolle an Konsolenanwendungen ist eigentlich dass du die direkt aus deiner Delphi-Anwendung über Pipes (StdIn, StdOut, StdErr) auslesen und füttern kannst wie der Mensch der das schwarze Konsolenfenster mit der Tastatur bedient. PS: Ja, dass es mit Jobs zu funktioniert bestätigt ![]() |
AW: ShellExecuteEx + TerminateProcess
Bist du sicher, dass der Prozess nicht beendet wird? Du killst cmd.exe, aber die Ausgabe kommt von ping.exe. Führt man eine CMD von Hand aus (mit ping auf irgendeinen Host) und killt per Task-Manager die cmd.exe, bleibt das Konsolenfenster dennoch offen und wird erst bei Abbruch der ping.exe (z.B. per Strg+C) geschlossen.
Grüße Dalai |
AW: ShellExecuteEx + TerminateProcess
![]() ![]() ![]() Aber ja, wenn es ein anderes Programm ausführt bringt das nicht viel.... |
AW: ShellExecuteEx + TerminateProcess
Zitat:
Ich habe auch schon versucht ein Ctrl+C an die Konsole zu schicken aber das hat auch nicht den gewünschten Effekt gebracht:
Delphi-Quellcode:
PostMessage(ShExecInfo.hProcess, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(ShExecInfo.hProcess, WM_KEYDOWN, VkKeyScan('c'), 0); PostMessage(ShExecInfo.hProcess, WM_KEYUP, VkKeyScan('c'), 0); PostMessage(ShExecInfo.hProcess, WM_KEYUP, VK_CONTROL, 0); |
AW: ShellExecuteEx + TerminateProcess
Zitat:
|
AW: ShellExecuteEx + TerminateProcess
Was passiert denn bei
Delphi-Quellcode:
Brauchst Du denn überhaupt eine Konsole als "Zwischenwirt"?
ShExecInfo.cbSize := SizeOf(ShellExecuteInfo);
ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := 'ping.exe'; ShExecInfo.lpParameters := '-t delphipraxis.net'; ShExecInfo.nShow := SW_SHOW; |
AW: ShellExecuteEx + TerminateProcess
Das kann hinten und vorne nicht klappen.
Erstens machst du PostMessage mit einem Handle auf den Prozess. Man schickt aber Messages an ein Fensterhandle (HWND). Zweitens interessieren sich Konsolenanwendungen herzlich wenig für Messages. Ich bleibe dabei, ich sehe zwei Möglichkeiten: 1. Man verbindet sich mit der Konsole des gestarteten Prozesses und schickt ihm ein Ctrl+C mittels ![]() oder 2. Man packt das Ding in einem Job und wenn man es wirklich hart abschießenb will schließt man einfach den Job. Ich nutze unter Windows die Jobs gerne, sie funktionieren zuverlässig und sind wirklich das Mittel der Wahl wenn man selbst gestartete Prozesse ordentlich und sicher verwalten will. |
AW: ShellExecuteEx + TerminateProcess
Zitat:
|
AW: ShellExecuteEx + TerminateProcess
Wieso nicht?
Delphi-Quellcode:
ShExecInfo.cbSize := SizeOf(ShellExecuteInfo);
ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := 'ping.exe'; ShExecInfo.lpParameters := '-t delphipraxis.net > c:\temp\datei_in_die_umgeleitet_werden.soll'; ShExecInfo.nShow := SW_SHOW; |
AW: ShellExecuteEx + TerminateProcess
Das hatte ich auch schon probiert, aber scheinbar weiß die ping.exe nicht, was sie mit dem ">" anfangen soll und beendet sich sofort beim Aufruf. So wie ich es verstanden habe ist die Umleitung mittels ">" eine Funktionalität der Konsole.
|
AW: ShellExecuteEx + TerminateProcess
Zitat:
|
AW: ShellExecuteEx + TerminateProcess
nur mal eine frage so am rande, geht es wirklich um "ping.exe" oder andere CLI anwendungen?
ping kann man ja per indy und konsorten auch ohne CLI haben, unsichtbar im hintergrund, auswerten und schreiben in eine datei etc.... |
AW: ShellExecuteEx + TerminateProcess
Zitat:
@shebang: Werden denn selbstgeschriebene Konsolenprogramme ausgeführt? Wenn ja, dann würde ich das Konzept überdenken und die Programme entsprechend der Anforderungen anpassen. Prozesse töten sollte immer einer der letzten Wege sein. Grüße Dalai |
AW: ShellExecuteEx + TerminateProcess
Zitat:
|
AW: ShellExecuteEx + TerminateProcess
Frag' bitte mal die Suchmaschine Deiner Wahl nach createprocess with pipe site:delphipraxis.net. Da sollten ein paar brauchbare Ansätze zu finden sein. Momentan kann ich aber nicht entscheiden, welcher der für Dich Richtige ist.
Der beste Ansatz ist vermutlich hier zu finden: ![]() |
AW: ShellExecuteEx + TerminateProcess
Zitat:
![]() Nachdem es gestartet wurde noch eine liste anfertigen. Prozessliste nach "CLIname.exe" (ping.exe) bei den neu dazugekommenen durchforsten und PID merken. Bei abbruch dann zuerst die PID abschießen anschließend die CLI von der du ja bereits das handle kennst. (In manchen situationen ändert sich das handle allerdings, das sollte man im hinterkopf haben) Wenn es wiederum doch nur ums pingen geht würde ich komplett auf CLI verzichten und per ![]() ![]() |
AW: ShellExecuteEx + TerminateProcess
Zitat:
![]() ![]() Benutzung ist folgendermaßen:
Delphi-Quellcode:
var
windowsJob: TJobObject; shellExecuteInfo: TShellExecuteInfo; begin (...) windowsJob := TJobObject.Create(); ShellExecuteEx(shellExecuteInfo); windowsJob.moveProcessTo(shellExecuteInfo.Handle); end; |
AW: ShellExecuteEx + TerminateProcess
Zitat:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var StartupInfo : TStartupInfo; SecAttr : TSecurityAttributes; command : string; filename : string; begin command := 'ping.exe -t delphipraxis.net'; filename := 'D:\output.txt'; ZeroMemory(@SecAttr, SizeOf(TSecurityAttributes)); SecAttr.nLength := SizeOf(SecAttr); SecAttr.bInheritHandle := True; fileHandle := CreateFile(PChar(filename), GENERIC_WRITE, FILE_SHARE_WRITE, @SecAttr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); ZeroMemory(@StartupInfo, SizeOf(TStartupInfo)); StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.hStdOutput := fileHandle; StartupInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; StartupInfo.wShowWindow := SW_HIDE; CreateProcess(nil, PChar(command), nil, nil, TRUE, 0, nil, nil, StartupInfo, ProcessInfo); end; procedure TForm1.Button2Click(Sender: TObject); begin TerminateProcess(ProcessInfo.hProcess, 0); CloseHandle(fileHandle); CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); end; |
AW: ShellExecuteEx + TerminateProcess
Schade das shebang Kommunikation mit mir vermeidet, sonst hätte ich meine timer-basierte CLI freie Lösung mal zeigen können, da es sich bis zum Ende ja doch nur um Ping gehandelt hat oder es war alles nur exemplarisch und ich bin schwer von begriff :-]
|
AW: ShellExecuteEx + TerminateProcess
Zitat:
|
AW: ShellExecuteEx + TerminateProcess
Zitat:
Das Gute an der gefundenen Lösung ist ja, dass sie (zumindest aus meiner Sicht) allgemeingültig ist. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:38 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz