Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   ShellExecute und Vordergrund (https://www.delphipraxis.net/157385-shellexecute-und-vordergrund.html)

Schwedenbitter 10. Jan 2011 14:26

ShellExecute und Vordergrund
 
Hallo,

zu ShellExecute gibt es eine Menge Themen. Möglicherweise zu viel, als dass ich meine Lösung finden konnte.

Ich habe eine Server-/Client-Anwendung. Üblicher Weise sendet der Server den Clients Pfad + Datei und der Client öffnet das. Es sind meistens OpenOffice-Dateien. Ich benutze daher ShellExecute, weil es mir zu kompliziert ist, in der Registry etc. pp. nach der Verknüpfung für die entsprechenden Dateiendungen zu suchen.

Wir haben bei uns aber auch eine TK-Anlage, die Faxe empfängt und diese unglückseeliger Weise als exe-Dateien ablegt. Genau darin besteht mein Problem:
Ich lasse den Client Pfad + Namen dieser exe-Dateien zukommen und sie werden über ShellExecute ebenfalls gestartet. Nur leider verschwindet das dann angezeigte Fenster der Fax-Anwendung immer hinter dem Fenster meiner Anwendung und es nervt, dieses über die Taskleiste in den Vordergrund holen zu müssen. Ich halte das für einen Fehler im Programm, was mir aber nicht weiterhilft.

Gibt es eine Möglichkeit, dass mit ShellExecute zu machen?

Ich habe jetzt mal ganz plmup folgendes probiert, was aber nicht funktioniert:
Delphi-Quellcode:
Procedure ForceToFront(Value: HWND);
Var
  Th1, Th2    : Cardinal;
Begin
  Th1:=GetCurrentThreadId;
  Th2:=GetWindowThreadProcessId(GetForegroundWindow, nil);
  AttachThreadInput(Th2, Th1, True);
  Try
    SetForegroundWindow(Value);
  Finally
    AttachThreadInput(Th2, Th1, False);
  End;
End;

Procedure TWFOpen.HandleFiles(Sender: TObject);
Var
  S      : String;
  Done   : Boolean;
  Inst   : HInst;
Begin
  Done:=(OpenFiles.Count = 0);
  While Not Done Do
  Begin
    S:=OpenFiles.Strings[0];
    // Alternative:
    // ForceToFront(self.Handle);
    Inst:=ShellExecuteA(self.Handle, 'open', PChar(S), nil, nil,
            SW_SHOWDEFAULT);
    ForceToFront(Inst);
    OpenFiles.Delete(0);
    Done:=(OpenFiles.Count = 0);
  End;
End;
Wenn ich als Alternative das ForceToFront zuvor aufrufe, dann klappt es. Allerdings habe ich dann das Problem, dass damit das Hauptfenster meiner Applikation ebenfalls im Vordergrund ist, was ich nicht will.

Ich habe auch schon herausgefunden, dass Inst nicht dasselbe wie das Fensterhandle ist und es schon deshalb nicht funktionieren kann. Allerdings könnte man meine Frage daher ggf. auch so umformulieren:
Wie komme ich über das von ShellExecute zurückgegebene HInst an das Handle des Fensters heran?

Gruß, Alex

Luckie 10. Jan 2011 15:33

AW: ShellExecute und Vordergrund
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1073683)
Wie komme ich über das von ShellExecute zurückgegebene HInst an das Handle des Fensters heran?

Shellexecute gibt nur einen Fehlercode zurück nicht mehr und nicht weniger.

Nimm entweder CreateProcess oder ShellexecuteEx.

Schwedenbitter 11. Jan 2011 10:06

AW: ShellExecute und Vordergrund
 
Zitat:

Zitat von Luckie (Beitrag 1073709)
Nimm entweder CreateProcess oder ShellexecuteEx.

Danke für den Tip. Ich habe das so versucht und ich habe auch schon die DP durchstöbert:
Delphi-Quellcode:
procedure TForm1.Memo1Click(Sender: TObject);
var
  ShExecInfo : SHELLEXECUTEINFO;
begin
  FillChar(ShExecInfo, SizeOf(SHELLEXECUTEINFO), 0);
  ShExecInfo.cbSize:=SizeOf(SHELLEXECUTEINFO);
  ShExecInfo.fMask:= SEE_MASK_NOCLOSEPROCESS;
  ShExecInfo.Wnd:=  self.Handle;
  ShExecInfo.lpVerb:='open';
  ShExecInfo.lpFile:=PChar('calc.exe');
  ShExecInfo.nShow:= SW_NORMAL Or SW_SHOWDEFAULT;
  ShellExecuteEx(@ShExecInfo);
  Memo1.Lines.Append('ShellExecuteEx:' + #09 + IntToStr(ShExecInfo.hProcess));
end;
Wenn ich das richtig verstehe, dann habe ich jetzt die Process-ID. Wie komme ich aber an das Fenster-Handle ran, damit ich mit den mir bekannten Funktionen das Fenster in den Vordergrund zwingen kann?

Delphi-Quellcode:
ShExecInfo.Wnd
, wie man anhand dieses Posts annehmen sollte, dürfte es nicht sein. Denn bei mir ist das immer 0. Und mit diesem Code (
Delphi-Quellcode:
function GetWndHandle(ProcessId: DWORD): HWND;
) erhalte ich auch immer nur 0.
Wenn ich das richtig verstehe, muss ich "nur" die Handles aller Fenster ermitteln, deren Process-IDs mittels
Delphi-Quellcode:
GetWindowThreadProcessId()
herausbekommen. Wenn dann eine der ermittelten mit
Delphi-Quellcode:
ShExecInfo.hProcess
übereinstimmt, habe ich mein Handle? Kann mir da bitte, bitte jemand mal Code oder einen Links posten? Ich habe bereits mehrere Themen dazu durchgelesen, steige aber nicht wirklich dahinter, wie ich
Delphi-Quellcode:
EnumWindows
verwenden muss. Ich habe zwar Code gefunden, wie man Fenster schließen kann, schaffe es aber nicht, den so umzustellen, dass ich stattdessen das Handle erhalte...

Wenn ich die Themen hier richtig verstanden habe, muss ich dann am Schluss auch noch
Delphi-Quellcode:
CloseHandle(ShExecInfo.hProcess);
aufrufen, oder?

Gruß, Alex

Schwedenbitter 11. Jan 2011 11:25

AW: ShellExecute und Vordergrund
 
Ich habe mich bemüht, mich hieran orientiert und es scheinbar zum Laufen bekommen:
Delphi-Quellcode:
Function FindHandle(Const ProcessId: THandle): HWND;

  Function EnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; Stdcall;
  Begin
    TList(lParam).Add(Pointer(hWnd));
    Result:=True;
  End;

Var
  hList : TList;
  PID   : DWord;
Begin
  Result:=0;
  hList:=TList.Create;
  Try
    EnumWindows(@EnumWindowsProc, LPARAM(hList));
    While (hList.Count > 0) Do
    Begin
      If (GetWindowThreadProcessId(HWND(hList.Items[0]), @PID) > 0) And
       (ProcessId = PID) Then
      Begin
        Result:=HWND(hList.Items[0]);
        Break;
      End;
      hList.Delete(0);
    End;
  Finally
    hList.Free;
  End;
End;
FindHandle bleibt aber immer 0. Was mache ich denn nun wieder verkehrt?

rollstuhlfahrer 11. Jan 2011 15:52

AW: ShellExecute und Vordergrund
 
Weil du keine ProzessID bekommst. Du bekommst ein Handle auf einen Prozess zurück, welches genauso funktioniert, wie das, was OpenProcess zurückliefert.
Du könntest ja mal versuchen, deinem Programm zu sagen, dass es einfach einen Schritt nach hinten machen soll. Somit müsste automatisch das Fax-Anzeige-Programm nach vorne kommen, oder ist das noch weiter hinten? - Dann mal doch CreateProcess anschauen, weil das viel mehr möglichkeiten bietet und gar nicht so schwer ist.

Bernhard

DeddyH 12. Jan 2011 08:01

AW: ShellExecute und Vordergrund
 
Ich habe dazu ein kurzes Beispiel "heruntergeschlumpert" (d.h. ohne Gewähr, PID ist ein privates DWORD-Feld des Formulars):
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
begin
  ZeroMemory(@StartupInfo,SizeOf(StartupInfo));
  StartupInfo.cb := SizeOf(StartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := SW_SHOW;
  if CreateProcess(nil, 'calc.exe', nil, nil, false, CREATE_NEW_CONSOLE or
                   NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo) then
    try
      PID := ProcessInfo.dwProcessId;
    finally
      CloseHandle(ProcessInfo.hProcess);
      CloseHandle(ProcessInfo.hThread);
    end;
end;

function EnumWindowsProc(Wnd: HWnd; aPID: DWORD): BOOL; stdcall;
var hProcess: DWORD;
begin
  GetWindowThreadProcessID(Wnd,hProcess);
  Result := hProcess <> aPID;
  if not Result then
    SetForegroundWindow(Wnd);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if PID <> 0 then
    EnumWindows(@EnumWindowsProc,PID);
end;
[edit] Wobei das zu Problemen führen kann, wenn der Prozess mehrere Fenster geöffnet hat, da ich einfach das zuerst gefundene nach vorn hole und dann aus der Schleife austrete. Vermutlich gibt es einen Weg, das MainForm zu ermitteln, leider kenne ich ihn nicht :( [/edit]


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