Ustawienie okna zewnętrznego programu na wierzchu, jeśli jest uruchomiony

0

Witam

Sprawdzam na formatce czy podany program jest już uruchomiony. Jeżeli nie uruchamiam go. Jeżeli tak to chcę wywołać ten program na wierzch ekranu. Niestety nie mogę znaleźć jak uruchomić zewnętrzny program na wierzch.

0

@Ice1 - a ten zewnętrzny program jest Twój, czy nie?

0

Może byc gdy zajdzie zdarzenie że nie jest uruchomiony to uruchamiam program. A może być wcześniej uruchomiony przez kogoś innego

2

Musisz pobrać uchwyt okna głownego tej aplikacji. Są funkcje do enumeracji procesów lub okien. Poczytaj na MSDN. Samo przywołanie aplikacji na wierzch to wysłanie czegoś takiego do uchwytu okna tejze aplikacji, jak poniżej widzisz w kodzie. Poniżej właśnie przykład zapobiegania uruchomieniu aplikacji więcej niż jeden raz, a w przypadku gdy jest już uruchomiona pokazania jej okna na pierwszy plan. Stała o nazwie HWND_BROADCAST powoduje rozesłanie komunikatu do wszystkich utworzonych okien głownych.

Plik projektu:

program uzywamy_t_brain_uzwamy_nie_spimy;

uses
  Forms,
  Windows,
{...}

{$R *.res}

begin
  CreateMutex(nil, False, Mutex_Name);
  if GetLastError = ERROR_ALREADY_EXISTS then
  begin
    SendMessage(HWND_BROADCAST, RegisterWindowMessage(Msg_Name), 0, 0);
    Halt;
  end;
  Application.Initialize;
  Application.CreateForm {...}
  Application.Run;
end.

W kodzie głownej formatki naszego programu (wycinek najważniejszych rzeczy):

const
  Mutex_Name = 'SomeSuperApp_by_You';
  Msg_Name = 'Restore_SomeSuperApp_App';
//...
var
  MyMsg : Longint;
  OldWindowProc : Pointer;
//...
function NewWindowProc(WindowHandle : hWnd; TheMessage : Longint; ParamW : WPARAM;  ParamL : LPARAM) : Longint stdcall;
begin
  if TheMessage = MyMsg then
  begin
    if IsIconic(Application.Handle) then
    begin
      ShowWindow(Application.Handle, SW_SHOW);
      ShowWindow(Application.Handle, SW_RESTORE);
    end
    else
    begin
      SetForeGroundWindow(Application.Handle);
    end;
    Result := 0;
    Exit;
  end;
  Result := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW, ParamL);
end;
//...
procedure TMainForm.FormCreate(Sender : TObject);
begin
//...
  MyMsg := RegisterWindowMessage(Msg_Name);
  OldWindowProc := Pointer(SetWindowLong(MainForm.Handle, GWL_WNDPROC, Longint(@NewWindowProc)));
//...
end;
//...

W przypadku większości apek pisanych pod Delphi 7, a może i nie tylko pod tą wersją. Jeżeli ktoś będzie miał jej używać na @$#!&@%*%@$@! Windowsie osiem, to należy dobrać się do obsługi komunikatów przez okno formatki głownej poprzez własnośc WindowProc i pamiętać aby przy zamykaniu aplikacji przywrócić oryginalne WindowProc. Inaczej możemy albo użytkownicy naszej aplikacji pod tą "cudowną" wersją systemu uświadczyć niestety jakichś access violationów. Albo co najlepsze nić nikomu nie mówiącego domyśłnego komunikatu o crashu przy zamykaniu aplikacji. I tylko takie coś nam/im pomoże wtedy.

0

Program nie jest mój ale jestem w stanie pozmieniać go bo mam kod źródłowy

3

Jezeli ma unikalną nazwę w belce tytułowej i/lub klasę okna, którą ustalisz jakimś spy'em, to najprościej będzie pobrać jego uchwyt przez FindWindow i wywołać SetForegroundwindow. Ewentualnie skorzystać z kodów, jakie dołaczyłem do tego posta. Aby uzyskać inaczej uchwyt programu. Kod pierwszego modułu jest pisany dawno i na szybko, więc do idealdnych nie należy. Natomiast drugi kod też jest stary, ale świeższy i ładniej oparty na klasach, więc zrobiony lepiej.

0

skorzystałem z rozwiązania get_hwnd_from_pid.pas. Wszystko fajnie działa dopóki aplikacja nie jest zminimalizowana. Gdy chcę aby aplikacja zminimalizowana wyskoczyła na wierzch nie działa.

0

No to co za problem wykorzystać kod, który podałem dla własnej aplikacji w funkcji obsługi komunikatów. Tylko zamiast Application.Handle podać uchwyt jaki uzyskałeś na podstawie PID. Próbowałeś w ogóle?

//...
uses
  get_hwnd_from_pid;

procedure TForm1.Button1Click(Sender : TObject);
var
  H : HWND;
begin
  H := PidToHandle($3704);
  if H > 0 then
  begin
    if IsIconic(H) then
    begin
      ShowWindow(H, SW_SHOW);
      ShowWindow(H, SW_RESTORE);
    end
    else
    begin
      SetForeGroundWindow(H);
    end;
  end;
end;
//...

Według mnie powinno zadziałać, dla Total Commandera działa. No chyba, że mamy operacje w tle, jak na przykład kopiowanie czy przenoszenie plików. Wtedy pokaże się tylko to okienko, ale nie problem wyenumerować okna głowne należące tylko do tego pidu i do nich wysłać odpowiednie komunikaty. To już sobie ogarnij sam.

0

Tak próbowałem przez to. Niestety przy niektórych aplikacjach nie działa. I nie ma zadań w tle.

0

No to nie wiem, według mnie mój kod zwraca uchwyt ok, nawet dla aplikacji Delphi z tym ukrytym oknem TApplication będącego rodzicem dla wszystkich formatek. Spróbuj więc enumerować okna, porównywać PIO z żądanym i do każdego okna o tym PID zrobić to co pokazałem w kodzie. Jeżeli nadal nie przywróci okna, to znaczy że to jakieś niestandardowe twory, które nie obslugują komunikatów. Albo nie wszystkie z nich są odbierane przez okno.

0

Sprawdziłem co zwraca funkcja ** PidToHandle(pid) ** i dla aplikacji zminimalizowanej i gdy jest pod spodem zwraca inne numery

Class Name = TMain; Title = Nagrody; HWND = 856316; Pid = 4420 pod spodem
Class Name = TApplication; Title = ; HWND = 1248852; Pid = 4420 - zminimalizowana

1

To dziwne, bo nie powinno, ale posłanie takich komunikatów do okna - formatki też powinno ją przywrócić.

  ShowWindow(Self.Handle, SW_SHOW);
  ShowWindow(Self.Handle, SW_RESTORE);
  SetForeGroundWindow(Self.Handle);
0

To zadziała. Tylko czy da się sprawdzić jakie okno aplikacja ma na wierzchu?

1

Na samym wierzchu to GetForegroundWindow. Inne możliwe funkcje do sprawdzania to IsIconic oraz IsWindowVisible.

1 użytkowników online, w tym zalogowanych: 0, gości: 1