Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   ShellExecuteEx + TerminateProcess (https://www.delphipraxis.net/207684-shellexecuteex-terminateprocess.html)

shebang 22. Apr 2021 11:32

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:
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;
Das Flag
Delphi-Quellcode:
SEE_MASK_NOCLOSEPROCESS
führt dazu, dass das Process handle in der Variablen
Delphi-Quellcode:
ShExecInfo.hProcess
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?

PS: CreateProcess verwende ich nicht, da dort die Umleiten der Ausgabe in eine Datei nicht funktioniert.

Der schöne Günther 22. Apr 2021 12:43

AW: ShellExecuteEx + TerminateProcess
 
Der Doku "How Processes are Terminated" nach:
Zitat:

(...)
For console processes, the default console control handler calls ExitProcess when the console receives a CTRL+C or CTRL+BREAK signal.
(...)
Da du den Prozess ja über seine eigene, neue Konsole laufen lässt ist wahrscheinlich der einfachste Weg, die Anwendung in einem Job laufen zu lassen und diesen dann notfalls zu beenden.


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 hier jemand. Trotzdem hätte ich gesagt dass der jetzige Ansatz wirklich nicht optimal ist.

Dalai 22. Apr 2021 13:28

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

KodeZwerg 22. Apr 2021 13:31

AW: ShellExecuteEx + TerminateProcess
 
Delphi-Referenz durchsuchenAttachConsole bzw Delphi-Referenz durchsuchenAllocConsole sollte doch funktioniert und im Cancel-Event dann Delphi-Referenz durchsuchenFreeConsole oder?

Aber ja, wenn es ein anderes Programm ausführt bringt das nicht viel....

shebang 22. Apr 2021 14:31

AW: ShellExecuteEx + TerminateProcess
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1487593)
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.

Die Daten, die in die Datei geschrieben werden sollen, benötige ich innerhalb meiner Delphi-Anwendung gar nicht. Die sind für eine spätere externe Auswertung vorgesehen. Ich möchte im Prinzip nur ein Konsolenprogramm starten und zu einem späteren Zeitpunkt wieder stoppen können. Die Konsole wird später gar nicht erst angezeigt, sondern soll unsichtbar im Hintergrund laufen.

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);

shebang 22. Apr 2021 14:40

AW: ShellExecuteEx + TerminateProcess
 
Zitat:

Zitat von Dalai (Beitrag 1487602)
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.

Komme ich denn irgendwie an das Handle von ping.exe, damit ich dem ein Strg+C schicken kann?

Delphi.Narium 22. Apr 2021 15:41

AW: ShellExecuteEx + TerminateProcess
 
Was passiert denn bei
Delphi-Quellcode:
 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;
Brauchst Du denn überhaupt eine Konsole als "Zwischenwirt"?

Der schöne Günther 22. Apr 2021 16:00

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 GenerateConsoleCtrlEvent

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.

shebang 22. Apr 2021 16:48

AW: ShellExecuteEx + TerminateProcess
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1487630)
Was passiert denn bei
Delphi-Quellcode:
 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;
Brauchst Du denn überhaupt eine Konsole als "Zwischenwirt"?

Dein Vorschlag funktioniert prinzipiell, TerminateProcess beendet den Prozess wie gewünscht. Allerdings ist dann die Umleitung der Ausgabe in eine Datei nicht möglich.

Delphi.Narium 22. Apr 2021 17:06

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;


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:09 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz