In diesem Kapitel soll es hauptsächlich darum gehen, wie man die eigene Anwendung in die "Taskbar Notification Area" minimieren lassen kann. In Foren wird ab und zu gefragt, wie man das bewerkstelligen kann. Bei nonVCL-Programmen ist dies relativ einfach. Beim Erzeugen des Fensters laden wir das gewünschte Symbol und weisen das Fenster-Handle zu (ganz so, wie es in den letzten Kapiteln demonstriert wurde):
WM_CREATE:
begin
NID.wnd := wnd;
NID.hIcon := LoadIcon(hInstance,'JIM');
end;
Und beim Beenden des Programms entfernen wir sicherheitshalber das TNA-Icon (auch so, wie es bereits besprochen wurde):
WM_DESTROY:
begin
Shell_NotifyIcon(NIM_DELETE,@NID);
{ ... }
end;
So weit nichts Neues.
Um auf das Minimieren des Fensters zu reagieren, gibt es zwei Wege, die wir gehen können. Einer wäre, die Nachricht "WM_SYSCOMMAND" zu bearbeiten, wenn der wParam den Wert "SC_MINIMIZE" enthält. Allerdings reagiert unser Programm dann nicht auf den globalen System-Hotkey WIN+M, mit dem man recht bequem alle Fenster minimieren kann (sofern Ihre Tastatur die Taste mit dem Windows-Logo enthält, natürlich!). Das heißt, unser Programm reagiert schon, aber es wird wirklich nur minimiert, nicht aber in die TNA "verschoben".
Besser ist daher die Bearbeitung der Nachricht "WM_SIZE", deren wParam den Wert "SIZE_MINIMIZED" enthält, wenn das Fenster minimiert wurde. Und diesmal funktioniert es auch mit den angesprochenen System-Hotkey:
WM_SIZE:
if(wp = SIZE_MINIMIZED) then
begin
if(Shell_NotifyIcon(NIM_ADD,@NID)) then
ShowWindow(wnd,SW_HIDE);
end else
Result := DefWindowProc(wnd,uMsg,wp,lp);
Zu beachten ist allerdings, dass die Nachricht "WM_SIZE" auch ausgelöst wird, wenn das Fenster maximiert oder anderweitig in seiner Größe verändert wird. Darum ja auch die Einschränkung im Code, mit der wir gezielt auf die Minimierung prüfen. Dennoch dürfen wir die die anderen Möglichkeiten nicht blockieren und müssen Sie deshalb an die Standardfensterprozedur "DefWindowProc" weiterleiten.
Wie dem auch sei, das Programm (s. Beispiel "OnMinimize.dpr") weist nun das gewünschte Verhalten auf und minimiert sich in die TNA.
Wollen Sie das gleiche Verhalten für Ihre VCL-Programme verwenden, dann liegt es auf der Hand das obige Verhalten entsprechend nachzubilden. Sie müssen also auch hier auf die Nachricht "WM_SIZE" reagieren, was beispielsweise so aussehen kann:
type
TForm1 = class(TForm)
{ ... }
private
procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;
In dieser privaten Prozedur erstellen Sie ebenfalls das TNA-Symbol und lassen den Button in der Startleiste verschwinden. Bei VCL-Programmen ist allerdings das TApplication-Objekt für diesen Button verantwortlich. Das Formular wird durch die Minimierung selbst bereits versteckt, so dass Sie hier also das Handle von TApplication benutzen müssen:
procedure TForm1.WMSize(var Message: TWMSize); begin if(Message.Msg = WM_SIZE) and (Message.SizeType = SIZE_MINIMIZED) then begin if(Shell_NotifyIcon(NIM_ADD,@NID)) then ShowWindow(Application.Handle,SW_HIDE) else inherited; end else inherited; end;
Eine weitere Möglichkeit wäre, direkt in die "WndProc" des Formulars einzugreifen und dort die o.g. Nachricht zu bearbeiten, etwa:
type
TForm1 = class(TForm)
{ ... }
protected
procedure WndProc(var Message: TMessage); override;
end;
Hierbei müssen Sie allerdings beachten, dass diese Prozedur wie in einem nonVCL-Programm der zentrale Anlaufpunkt für alle Arten von Nachrichten ist. Sie dürfen also keine blockieren, sondern Sie dürfen nur die gewünschte bearbeiten und müssen alle anderen weiterleiten.
Dabei kommt es auf die Art und Weise an, wie Sie das tun. In meinem Beispiel wird die Standardprozedur am Ende generell aufgerufen, so dass bei einer evtl. Nachrichtenbearbeitung die Prozedur vorher mit "exit" verlassen werden sollte:
procedure TForm1.WndProc(var Message: TMessage); begin case Message.Msg of WM_SIZE: if(Message.wParam = SIZE_MINIMIZED) then begin if(Shell_NotifyIcon(NIM_ADD,@NID)) then begin ShowWindow(Application.Handle,SW_HIDE) exit; end; end;
{ ... } end;
inherited WndProc(Message); end;
So weit die Theorie. In der Praxis scheiterten beide Versuche bei mir (Delphi 5 Pro) allerdings daran, dass SIZE_MINIMIZED ignoriert wird. Warum auch immer ...
Wenn Sie das Flag testweise durch sein Gegenstück SIZE_MAXIMIZED (= die Anwendung wurde maximiert) ersetzen, dann erscheint das TNA-Symbol, und der Button in der Startleiste verschwindet. Wie gesagt: theoretisch sollte es also auch beim Minimieren funktionieren ...
Möglicherweise handelt es sich hierbei aber auch "nur" um einen Bug von Delphi 5. Vielleicht ist das in Ihrer Delphi-Version auch anders bzw. (falls es ein Bug ist:) behoben, so dass Sie obige Anregungen ausprobieren können.
Jedenfalls wollte ich Ihnen den Vorschlag nicht vorenthalten, auch wenn er bei mir nicht funktioniert.