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.
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.
uruchom a potem wyslij MESSAGE,
http://stackoverflow.com/questions/6115296/delphi-how-to-send-command-to-other-application
@Ice1 - a ten zewnętrzny program jest Twój, czy nie?
Może byc gdy zajdzie zdarzenie że nie jest uruchomiony to uruchamiam program. A może być wcześniej uruchomiony przez kogoś innego
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.
Program nie jest mój ale jestem w stanie pozmieniać go bo mam kod źródłowy
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.
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.
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.
Tak próbowałem przez to. Niestety przy niektórych aplikacjach nie działa. I nie ma zadań w tle.
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.
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
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);
To zadziała. Tylko czy da się sprawdzić jakie okno aplikacja ma na wierzchu?
Na samym wierzchu to GetForegroundWindow. Inne możliwe funkcje do sprawdzania to IsIconic oraz IsWindowVisible.