Witam,
czy jest możliwość zminimalizowania do traya programem delphi innej, zewnętrznej aplikacji która nie ma możliwości minimalizowania do traya?
Jeżeli tak to proszę o wskazówki :)
OK, rozumiem,
ale jak minimalizowac i umieszczac ikone w tray?
a ta zmienna NotifRec
to co to jest?
- Rejestracja:prawie 20 lat
- Ostatnio:około 2 godziny
- Lokalizacja:Gorlice
2 parametr funkcji Shell_NotifyIcon to wskaźnik na rekord który zawiera między innymi uchwyt okna które chcesz zminimalizować (uwaga leniwy przykład zero obsługi komunikatów i usuwania ikony z traya)
uses
shellapi;
procedure TForm1.Button1Click(Sender: TObject);
const
WINDOW_TITLE = 'Kalkulator';
var
hWnd: THandle;
TrayRec: TNotifyIconData;
begin
hWnd:= FindWindow(nil, WINDOW_TITLE);
ZeroMemory(@TrayRec, SizeOf(TrayRec));
TrayRec.cbSize:= SizeOf(TrayRec);
TrayRec.Wnd:= hWnd;
TrayRec.uFlags:= NIF_ICON;
TrayRec.hIcon:= Application.Icon.Handle;
if Shell_NotifyIcon(NIM_ADD, @TrayRec) then
SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
end;

- Rejestracja:prawie 17 lat
- Ostatnio:około 3 lata
- Lokalizacja:Szczecin
- Postów:4191
Pozwoiliłem sobie zatwierdzić odpowiedź @kAzek'a jako rozwiązanie. Jednak nie jest ono według mnie kompletne. Ponieważ między innymi będzie problem z ikonką i z obsługą menu. Nie da się niestety łatwo wedlug mojej wiedzy dostać do popup menu będącego pod TrayIconami obcych programów, do których kodu źródlowego nie mamy dostępu. Można wykombinować tak jak pokazuje w kodzie poniżej. Rozwiązanie tylko dla nazw plików Ansi. Widoczna będzie ikonka obcej aplikacji. Dwuklikiem na ikonkę przywrócimy aplikację. Przy zamykaniu aplikacji wywołującej aplikacja zostanie przywrócona.
Ponieważ sposób, ktory zaprezentował swoim kodem @kAzek może być wraz z dodaniem obslugi ikonki przeze mnie. Z tym, że niestety nadal pozostaje kwestia obsługi ikonki. Wiadomo, że nie "podczepimy" się pod obcy proces bez injekcji / wrappera dll. A ustawiając pole rekordu danych ikonki Wnd
na Handle tego znalezionego okna, nie obsłużymy komunikatów. Natomiast ustawiając na Handle naszego okna ikonka zniknie nam po zamknięciu apki. Ot taki minus. Toteż ja w swoim pluginie dla WinAMP'a, który trochę inaczej realizuje minimalizowanie do TrayIkonki, symulowałem trzymanie Shift'a z małym Sleep'em. Ponieważ nie wyodrębniłem w żaden sposób parametrów dla komunikatu WM_COMMAND
lub podobnego - do wysłania oknu głownemu aby to schowało się do TrayIkonki. Nie uzyskałem też podpowiedzi na ich forum supportu, wiec tak zostało.
Na szczęście pluginem można założyć hook na WH_CBT
i uzyskać możliwość reakcji zanim zostanie dokonana minimalizacja. Jeżeli docelowy program, z którym tak chce kombinować przez minimalizacje do TrayIkonki posiada taką możłiwość i można go z jakimś combo zmimimalizować do traya z poprawnym menu i reagowaniem, to ja bym tak kombinował. Ewentualnie zawsze jeżeli bardzo chcesz udoskonalić jakiś program, żeby mógł się chować do ikonki w trayu, a nie do paska. To trzeba mozolnie napisać wrapper na którąś z systemowych dllek dla tego programu. W niej skorzystać z rzeczonego Hooka na okno programu i dorobić własną trayiconkę z reakcją na klawisze oraz menu.
Zaraz @babubabu mi zarzuci, że ciągle ostatnio musi czytać o technice wrappowania dllek, ale to na prawdę potężna możliowść. Może machne o tym artykuł jak znajdę trochę czasu i będzie zainteresowanie. A korzystająć z faktu, żę większość dllek systemowych i w ogółe przez LoadLibrary
czy statycznie najpierw jest wyszukiwana z katalogu programu, to można taką dllkę z własnym kodem tam wrzucić, a do oryginalnych funkcji jakie należy exportować można się odwołać do systemowej dllki. Takie kombinacje przydają się nie tylko w starszych grach żeby dobrze się wyświetlały pod Windowsami od Visty wzwyż. Można również zrobić proste poprawki i próbowac udoskonalić zachowanie programu, jeżeli nie wszystkie jego zachowania nam odpowiadają. Tyle. Sorry za rozpisanie się ;)
//...
uses
ShellApi, PSApi;
const
Window_Title = 'Kalkulator';
WM_TOOLTRAYICON = WM_USER + 1;
var
DestH : THandle;
OldWindowProc : Pointer;
IconData : TNotifyIconData;
function GetIconFromHandle(WindowHandle : HWND) : HICON;
function ProcessFullPath(Pid : DWORD) : string;
var
AHandle : THandle;
begin
Result := '';
AHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, Pid);
if AHandle <> 0 then
begin
try
SetLength(Result, MAX_PATH);
if GetModuleFileNameEx(AHandle, 0, PChar(Result), MAX_PATH) > 0 then
begin
SetLength(Result, StrLen(PChar(Result)));
end
else
begin
Result := '';
end;
finally
CloseHandle(AHandle);
end;
end;
end;
function ProcessFullPath64Bit(Pid : DWORD) : string;
const
PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
Len : DWord;
AHandle, DllHandle : THandle;
QueryFullProcessImageNameA : function(HProcess : THandle; dwFlags : DWord; lpExeName : PAnsiChar; lpdwSize : PDWord) : Bool; stdcall;
begin
Result := '';
DllHandle := LoadLibrary('kernel32.dll');
if DllHandle > 0 then
begin
QueryFullProcessImageNameA := GetProcAddress(DllHandle, 'QueryFullProcessImageNameA');
if Assigned(QueryFullProcessImageNameA) then
begin
AHandle := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, Pid);
if AHandle <> 0 then
begin
Len := MAX_PATH;
SetLength(Result, Len - 1);
QueryFullProcessImageNameA(AHandle, 0, PAnsiChar(Result), @len);
SetLength(Result, Len);
CloseHandle(AHandle);
end;
end;
FreeLibrary(DllHandle);
end;
end;
var
Pid : DWORD;
ProcesPath : string;
FileInfo : SHFILEINFO;
begin
Result := 0;
if ISWindow(WindowHandle) then
begin
GetWindowThreadProcessId(WindowHandle, Pid);
ProcesPath := ProcessFullPath(Pid);
if ProcesPath = '' then
begin
ProcesPath := ProcessFullPath64Bit(Pid)
end;
SHGetFileInfo(PChar(ProcesPath), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICON or SHGFI_LARGEICON);
Result := FileInfo.hIcon;
end;
end;
procedure RestoreApp;
begin
if (IsWindow(DestH)) and (ISIconic(DestH)) then
begin
ShowWindow(DestH, SW_SHOW);
ShowWindow(DestH, SW_RESTORE);
Shell_NotifyIcon(NIM_DELETE, @IconData);
end;
end;
function NewWindowProc(WindowHandle : hWnd; TheMessage : Longint; ParamW : Longint; ParamL : Longint) : Longint stdcall;
begin
case TheMessage of
WM_TOOLTRAYICON :
begin
case ParamL of
WM_LBUTTONDBLCLK :
begin
RestoreApp;
end;
end;
Result := 0;
Exit;
end;
WM_DESTROY :
begin
RestoreApp;
end;
end;
Result := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW, ParamL);
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
DestH := FindWindow(nil, Window_Title);
if DestH > 0 then
begin
if OldWindowProc = nil then
begin
OldWindowProc := Pointer(SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(@NewWindowProc)));
end;
ZeroMemory(@IconData, SizeOf(IconData));
with IconData do
begin
cbSize := SizeOf(IconData);
Wnd := Self.Handle;
uFlags := NIF_MESSAGE + NIF_ICON;
hIcon := GetIconFromHandle(DestH);
uCallbackMessage := WM_TOOLTRAYICON;
end;
if Shell_NotifyIcon(NIM_ADD, @IconData) then
begin
SendMessage(DestH, WM_SYSCOMMAND, SC_MINIMIZE, 0);
ShowWindow(DestH, SW_HIDE);
end;
end;
end;



