Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Externes Programm starten, beenden, in den Vordergrund holen (https://www.delphipraxis.net/149250-externes-programm-starten-beenden-den-vordergrund-holen.html)

NetSonic 17. Mär 2010 14:29


Externes Programm starten, beenden, in den Vordergrund holen
 
Hallo liebe User der DP,

ich stehe etwas auf dem Schlauch wegen folgendem Problem:
Ich möchte aus meinem Programm heraus eine weitere Anwendung starten, falls Sie noch nicht gestartet wurde.
Wurde Sie bereits gestartet, soll die Anwendung in den Vordergrund geholt und nicht nochmals gestartet werden.
Wenn ich das "Hauptprogramm" beendete, will ich prüfen ob die weitere Anwendung auch noch läuft und diese dann ggf. auch beenden.

Ich habe schon mit ShellExecuteEx usw. rumprobiert und mir die Handles zurückgeben lassen, aber irgendwie mache ich wohl etwas falsch.
Ich bekomme zwar einen Cardinal-Wert zurück, aber dieser existiert auch noch, wenn die Anwendung schon beendet wurde und dann startet Sie nicht nochmal...

Funktion zur Ausführung der Anwendung:
Delphi-Quellcode:
function ExecAndWait(Filename, Params: String;
                     WindowState: Word = SW_SHOWNORMAL; Wait : Boolean = False): Cardinal;
var
  {$IFDEF UNICODE} ShExecInfoW: SHELLEXECUTEINFOW; {$ENDIF}
  ShExecInfoA: SHELLEXECUTEINFOA;
// MSDN: ShellExecuteEx, ShellExecuteInfo
begin
  Result := 0;
  if (Filename = '') or not FileExists(FileName) then
    exit;
  {$IFDEF UNICODE}
  if Win32IsUnicode then
  begin
    ProgramStarting := True;
    ZeroMemory(@ShExecInfoW, SizeOf(ShExecInfoW));
    ShExecInfoW.Wnd         := GetForegroundWindow;
    ShExecInfoW.cbSize      := SizeOf(SHELLEXECUTEINFOW);
    ShExecInfoW.fMask       := SEE_MASK_NOCLOSEPROCESS;
    ShExecInfoW.lpVerb      := 'open';
    ShExecInfoW.lpFile      := PWideChar(WideString(Filename));
    ShExecInfoW.lpParameters := PWideChar(WideString(Params));
    ShExecInfoW.lpDirectory := PWideChar(WideString(ExtractFileDir(Filename)));
    ShExecInfoW.nShow       := WindowState;

    try
      ShellAPI.ShellExecuteExW(@ShExecInfoW);
      Result := ShExecInfoW.hProcess;
      if Wait then WaitForSingleObject(ShExecInfoW.hProcess, INFINITE);
    finally
      CloseHandle(ShExecInfoW.hProcess);
      ProgramStarting := False;
    end;
  end
  else
  {$ENDIF}
  begin
    ZeroMemory(@ShExecInfoA, SizeOf(ShExecInfoA));
    ShExecInfoA.Wnd         := GetForegroundWindow;
    ShExecInfoA.cbSize      := sizeof(SHELLEXECUTEINFOA);
    ShExecInfoA.fMask       := SEE_MASK_NOCLOSEPROCESS;
    ShExecInfoA.lpVerb      := 'open';
    ShExecInfoA.lpFile      := PAnsiChar(AnsiString(Filename));
    ShExecInfoA.lpParameters := PAnsiChar(AnsiString(Params));
    ShExecInfoA.lpDirectory := PAnsiChar(AnsiString(ExtractFileDir(Filename)));
    ShExecInfoA.nShow       := WindowState;

    try
      ShellExecuteExA(@ShExecInfoA);
      Result := ShExecInfoA.hProcess;
      if Wait then WaitForSingleObject(ShExecInfoA.hProcess, INFINITE);
    finally
      CloseHandle(ShExecInfoA.hProcess);
    end;
  end;
end;
Aufruf:
Delphi-Quellcode:
var
 cMod: Cardinal;
begin
if (IsWindow(cMod)) then
begin
     ShowWindow(cMod, SW_NORMAL);
     SetForegroundWindow(cMod);
end
else begin
     cMod := ExecAndWait(ExtractFilePath(Application.ExeName)+'\mod\newapp.exe', '', SW_SHOWNORMAL, False);
end;
Hat jemand einen Tipp für mich?

Gruß
NetSonic

DeddyH 17. Mär 2010 15:34

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Du verwechselst Prozess- und Fensterhandles. Du könntest mit Delphi-Referenz durchsuchenEnumWindows alle Fenster durchgehen und mit Delphi-Referenz durchsuchenGetWindowThreadProcessID deren Prozesshandle ermitteln und mit Deinem vergleichen.

NetSonic 17. Mär 2010 15:55

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Hm, ok

also liefert mir die Funktion das Fenster-Handle, aber nicht das Prozess-Handle zurück?!?
Wie komme ich denn am effektivsten mit dem Fenster-Handle an das Prozess-Handle.
Kann ich mir das nicht auch direkt in der Funktion zurückgeben lassen?
Oder anhand des ExeNamens den Prozess-Handle ermitteln?

DeddyH 17. Mär 2010 15:58

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Zitat:

Delphi-Quellcode:
Result := ShExecInfoA.hProcess;

Du hast das Prozesshandle.

NetSonic 17. Mär 2010 16:01

Re: Externes Programm starten, beenden, in den Vordergrund h
 
:wall:

Ich habe also das Prozess-Handle und benötige das Fenster-Handle?!
Und das muss ich mir mit EnumWindows holen? Richtig?!?

DeddyH 17. Mär 2010 16:02

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Jepp, wie oben beschrieben. Es mag evtl. noch andere Wege geben, aber dieser fällt mir immer zuerst ein.

NetSonic 19. Mär 2010 07:43

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Guten Morgen,

ich habe mich jetzt mal mit Deinen Vorschlägen auseinander gesetzt und folgendes probiert:

Delphi-Quellcode:
Type
  TEnumData = Record
    hW: HWND;
    pID: DWORD;
  End;

Function EnumProc( hw: HWND; Var data: TEnumData ): Bool; stdcall;
  Var
    pID: DWORD;
  Begin
    Result := True;
    If (GetWindowLong(hw, GWL_HWNDPARENT) = 0) and
       (IsWindowVisible( hw ) or IsIconic(hw)) and
       ((GetWindowLong(hw, GWL_EXSTYLE) and WS_EX_APPWINDOW) <> 0)
    Then Begin
      GetWindowThreadProcessID( hw, @pID );
      If pID = data.pID Then Begin
        data.hW := hW;
        Result := False;
      End; { If }
    End; { If }
  End; { EnumProc }

Function WindowFromProcessID( pID: DWORD ): HWND;
  Var
    data: TEnumData;
  Begin
    data.pID := pID;
    data.hW := 0;
    EnumWindows( @EnumProc, longint(@data) );
    Result := data.hW;
  End;
Jetzt will ich prüfen, ob das Fenster vorhanden ist:

Delphi-Quellcode:
if (WindowFromProcessID(cMod) <> 0) then
begin
     ShowWindow(WindowFromProcessID(cMod), SW_NORMAL);
     SetForegroundWindow(WindowFromProcessID(cMod));
end
else begin
     cMod := ExecAndWait(ExtractFilePath(Application.ExeName)+'\mod\newapp.exe', '', SW_SHOWNORMAL, False);
end;
Allerdings gibt mir die Funktion "WindowFromProcessID" immer 0 zurück. Mach ich da einen Denkfehler?

DeddyH 19. Mär 2010 07:48

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Tja, wenn der Code von Experts-Exchange nicht funktioniert, weiß ich im Moment auch nicht weiter :gruebel:

Der.Kaktus 19. Mär 2010 08:02

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Hallo,

wenn es um Processe etc. geht schau Dir mal diese Tools Processes an..funktionieren bei mir prima.

NetSonic 19. Mär 2010 08:36

Re: Externes Programm starten, beenden, in den Vordergrund h
 
Tja, da stellt sich mir jetzt auch die Frage, woran das liegen könnte.
Habe mir den Code jetzt wieder und wieder angesehen, aber ich finde das Problem nicht.
Ich habe die beiden Funktionen in eine externe Unit ausgelagert. Aber daran wird es ja wohl nicht liegen?!?

+++ edit +++
Ich habe es jetzt mit FindWindow gelöst. Der Klassename der Programms ist nämlich immer eindeutig, entgegen dem Programm-Titel...


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:20 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