AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Externes Programm mit ShellExecuteEx starten
Thema durchsuchen
Ansicht
Themen-Optionen

Externes Programm mit ShellExecuteEx starten

Ein Thema von schwa226 · begonnen am 7. Nov 2008 · letzter Beitrag vom 22. Jan 2009
Antwort Antwort
Seite 1 von 2  1 2      
schwa226

Registriert seit: 4. Apr 2008
400 Beiträge
 
#1

Externes Programm mit ShellExecuteEx starten

  Alt 7. Nov 2008, 19:23
Hi,

ich habe ein Programm, dass ich per ShellExecuteEx starte.

mit
Delphi-Quellcode:
     repeat
       Application.ProcessMessages;
       GetExitCodeProcess(SEInfo.hProcess, ExitCode) ;
     until (ExitCode <> STILL_ACTIVE) or
Application.Terminated;
warte ich bis es beendet wurde.

Geht auch einwandfrei!

Nun möchte ich aber ein Programm starten, dass einen anderen Prozess startet und sich selber dann beendet:

Start.exe wird gestartet -> die Start.exe startet dann das MainProgramm.exe -> Start.exe wird wieder beendet.

Nun bekomme ich natürlich als ExitCode 0 zurück und mein Programm glaubt das das Programm beendet wurde (was eigentlich auch stimmt). Aber das eigentliche Hauptprogramm läuft aber noch und auf dieses will ich warten!

Was gäbe es hier für Möglichkeiten? Eventuell einfach eine Schleife mit FindWindow?

[edit=SirThornberry]Code Tags in delphi Tags geändert - nächstes mal bitte richtige Tags verwenden - Mfg, SirThornberry[/edit]
[edit=SirThornberry]Titel geändert - Mfg, SirThornberry[/edit]
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: Externes Programm mit ShellExecuteEx per starten

  Alt 7. Nov 2008, 19:32
Die saubere Lösung verwendet Jobs. Jobs sind Sandkasten für Prozesse. Wenn ein Prozess in einem Job ist, sind seine Kindprozesse auch in dem Job (sofern der Besitzer des Jobs und der Prozess nicht beide sagen, dass dem nicht so sein soll). Du kannst dann die Anzahl aktiver Prozesse im Job abfragen. Wenn sie Null ist, kehrst du zurück. Für einen ereignisgesteuerten Ansatz kann man dem Job einen IO Completion Port zuweisen, welcher eine Nachricht erhält, wenn alle Prozesse beendet sind. Das muss allerdings in einem eigenen Thread geschehen, da es dann nicht möglich ist, auf Fensternachrichten zu reagieren.


Deine bisherige Lösung ist übrigens nicht optimal, da durch die Schleife unnötig CPU-Zeit verbraucht wird. Korrekt wäre es, mit MsgWaitForMultipleObjects auf das Handle zu warten.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
schwa226

Registriert seit: 4. Apr 2008
400 Beiträge
 
#3

Re: Externes Programm mit ShellExecuteEx per starten

  Alt 7. Nov 2008, 20:13
Gibt es auch einen Info-Link zu dem Job Handling?

Suche per Google hat nichts gebracht

Danke!
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#4

Re: Externes Programm mit ShellExecuteEx per starten

  Alt 7. Nov 2008, 20:24
Job Objects
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
schwa226

Registriert seit: 4. Apr 2008
400 Beiträge
 
#5

Re: Externes Programm mit ShellExecuteEx per starten

  Alt 10. Nov 2008, 08:53
Danke für den MSDN Link!

Habe jetzt vollgendes Versucht:

Zuerst einen Job anlegen:
Code:
hJob := CreateJobObject(nil,'Test App JOB');
Dann einen Process mit CreatProcess starten:
Code:
..
..
hProcess := RunProcess('notepad.exe',SW_SHOW,False,ProcID);
..
..
function RunProcess(FileName: string; ShowCmd: DWORD; wait: Boolean; ProcID: PDWORD): Longword;
var
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
  ExitInfo  : PExitThreadDebugInfo;
begin
  FillChar(StartupInfo, SizeOf(StartupInfo), #0);
  StartupInfo.cb         := SizeOf(StartupInfo);
  StartupInfo.dwFlags    := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
  StartupInfo.wShowWindow := ShowCmd;


  if not CreateProcess(nil,@Filename[1],nil,nil,False,CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,nil,nil,StartupInfo,ProcessInfo) then
  Result := WAIT_FAILED
  else
  begin

    AssignProcessToJobObject(hJob,ProcessInfo.hProcess);


    if wait = FALSE then
    begin
    //  if ProcID <> nil then ProcID^ := ProcessInfo.dwProcessId;
      exit;
    end;
    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    GetExitCodeProcess(ProcessInfo.hProcess, Result);
  end;
  if ProcessInfo.hProcess <> 0 then
    CloseHandle(ProcessInfo.hProcess);
  if ProcessInfo.hThread <> 0 then
    CloseHandle(ProcessInfo.hThread);
end;
Wenn es gestartet wurde mache ich mit AssignProcessToJobObject(hJob,ProcessInfo.hProcess ); den Process zu dem Job.

Wie kann ich nun überprüfen ob der Job noch Prozesse enthaltet?

Ich habe mit QueryInformationJobObject herumprobiert, jedoch ohne Erfolg!

Gibt es dazu noch ein Beispiel?

Auf jeden Fall scheint das mit dem Assignen zu funktionieren, denn wenn ich
Code:
TerminateJobObject(hJob,Exitcode);

CloseHandle(hJob);
mache schließt sich Notepad wieder!
  Mit Zitat antworten Zitat
schwa226

Registriert seit: 4. Apr 2008
400 Beiträge
 
#6

Re: Externes Programm mit ShellExecuteEx per starten

  Alt 11. Nov 2008, 12:43
Habe jetzt mit
Delphi-Quellcode:

type
      PJobObjectBasicProcessIDList = ^TJobObjectBasicProcessIDList;
      TJobObjectBasicProcessIDList = Record
          NumberOfAssignedProcesses : DWORD;
          NumberOfProcessIdsInList : DWORD;
          ProcessIdList : Array[0..0] of ULONG;
      End;

var

  Info: TJobObjectBasicProcessIDList;
  Len : Cardinal;




Result := QueryInformationJobObject(hJob,JobObjectBasicProcessIdList,@Info,SizeOf(Info),@Len);
geschafft nachzusehen ob Prozesse im Job sind. Das geht auch! Starte ich einmal oder zweimal Notepad es ist immer in der Info.NumberOfAssignedProcesses die richtige Anzahl.

Wie ist jetzt am besten hier im Programm stehen zu bleiben bis Info.NumberOfAssignedProcesses = 0?

Und zwar so, dass das Programm aber noch andere Funktionen bearbeiten kann.

Mit einem repeat until? WaitForSingleObject?
Wenn diese beiden Methoden probiere ist ja mein Programm blockiert, oder?

Es soll ja das externe Programm gestartet werden - Check ob's läuft - wenn's läuft andere Funktionen ausführen wie z.B. Keyboard Events rüberschicken usw. - wenn das externe Programm beendet wird fährt auch mein Programm nieder.
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: Externes Programm mit ShellExecuteEx per starten

  Alt 11. Nov 2008, 14:29
Es empfiehlt sich eher, über JobObjectBasicAccountingInformation und das Struktur-Element ActiveProcesses zu gehen. Bei der Prozess-ID-Liste sind vermutlich auch die terminierten Prozesse enthalten, oder zumindest jene, auf die noch jemand ein Handle hält.

Beim Warten darauf, dass alle Prozesse beenden werden, wird es kompliziert. Man kann zwar auf einen Job warten, das Objekt wird aber nicht etwa signalisiert, wenn alle Prozesse beendet sind, nein, es wird signalisiert, wenn die gesetzte Job-Zeit-Grenze erreicht ist (eigentlich sind Jobs dazu da, einer Gruppe von Prozessen Grenzen, z.B. für die Ausführungszeit und den Speicherverbrauch, zu geben, also eine Art Sandbox). Warum Microsoft das so eingerichtet hat, ist mir ein Rätsel. Um auf das Ende aller Prozess in einem Job zu warten und gleichzeitig Nachrichten zu verarbeiten, muss ein eigener Thread eingesetzt werden.
Zitat von Apollonius:
Für einen ereignisgesteuerten Ansatz kann man dem Job einen IO Completion Port zuweisen, welcher eine Nachricht erhält, wenn alle Prozesse beendet sind. Das muss allerdings in einem eigenen Thread geschehen, da es dann nicht möglich ist, auf Fensternachrichten zu reagieren.
Für diese Technik musst du zuerst einen IO Completion Port erstellen (CreateIoCompletionPort). Mit SetInformationJobObject kannst du dann den Port für Benachrichtigungen eintragen. Auf Benachrichtigungen wartest du mit GetQueuedCompletionStatus. Und genau dort liegt das Problem: Es ist weder möglich, auf weitere Objekte zu warten, noch kann man auf Fensternachrichten oder APCs warten (letzteres geht ab Windows Vista mit GetQueuedCompletionStatusEx). Daher solltest du am Anfang deines Programms einen Thread starten, der mit unbegrenztem Timeout auf einen Completion Port wartet. Mit einem beliebigen Mechanismus kann er dem Hauptthread dann die Nachrichten zugänglich machen. Beenden kannst du den Thread, indem du mit PostQueuedCompletionStatus eine eigene Nachricht verschickst, die der Thread erkennt. Daraufhin sollte er sich beenden.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
nat

Registriert seit: 10. Nov 2005
216 Beiträge
 
RAD-Studio 2009 Pro
 
#8

Re: Externes Programm mit ShellExecuteEx starten

  Alt 11. Nov 2008, 15:35
lacht mich nicht aus, aber in welcher unit is denn CreateJobObject etc deklariert?
ich finde die nicht und selber deklarieren is doch recht viel tipperei ^^
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: Externes Programm mit ShellExecuteEx starten

  Alt 11. Nov 2008, 15:53
In Windows.pas ist es tatsächlich nicht deklariert. Entweder du deklarierst es selbst oder nimmst die Units von anderen Leuten. JwaWindows von den Jedis enthält (fast) alles, was man an C-Übersetzungen benötigt.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
nat

Registriert seit: 10. Nov 2005
216 Beiträge
 
RAD-Studio 2009 Pro
 
#10

Re: Externes Programm mit ShellExecuteEx starten

  Alt 11. Nov 2008, 16:13
bin jetzt auch bei den jedis gelandet.
kannte die zwar, aber bin bisher auch immer ohne die ausgekommen.
nun bin ich mal nich drumrum gekommen ^^
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:33 Uhr.
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