My application has an option for the users to run it only in the system tray, and not in the task bar. This worked fine when my application was built by Delphi 6. After switching to Delphi XE2 it no longer functions.
I’ve messed with it some, and I have this working for Windows 7, but when running on Windows XP I still have a problem. The application correctly hides from the task bar, and shows in the system tray. But when I create and show any additional form, the icon shows up in Windows XP.
procedure TfrmAppointment.HideWindowFromTaskbar;
var
TaskbarList: ITaskbarList;
begin
Application.MainFormOnTaskBar := False;
// Windows 7 seems to behave differently. This seems to fix it.
if (CheckWin32Version(6, 1)) then
begin
// We are in Win7, and we requested the tray.
TaskbarList := CreateComObject(CLSID_TaskbarList) as ITaskbarList;
TaskbarList.HrInit;
TaskbarList.DeleteTab(Application.Handle);
end
else
begin
// Previous code from D6 days
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE, GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
ShowWindow(Application.Handle, SW_SHOWNOACTIVATE);
end;
end;
That code is ran if the user chooses the option to show the application in the system tray. It works fine on all versions of Windows I’ve tested on. On Windows XP, however, when I show any child form, the application instantly shows up in the taskbar. In Windows 7 all is fine.
Any ideas what I’m missing?
I should add that I know this is likely the same question as Hide the Main Form in a Delphi 2009 Application, however I already have the MainFormOnTaskBar being set, so that answer does not seem to apply.
[EDIT:] To be more specific, I’m adding additional information here. This application has two modes: Show in task bar, and show in system tray.
The first mode is the same as any normal application. The application exists only in the task bar. It minimizes to the task bar. It restores from the task bar.
The second mode behaves exactly the same, BUT that task bar icon instead exists in the system tray only. So, when a user minimizes the application, I intercept that message, grab the TRect for ‘Shell_TrayWnd’/’TrayNotifyWnd’, and call DrawAnimatedRects() to simulate the minimize to the tray. Then I hide the main form. On message from the system tray I draw the same animation rects in reverse, and make it visible again. While the form is visible it does not show in the task bar.
This all works perfectly fine in all Windows versions.
The specific issue I am having is that when any other form gets shown, Windows XP is creating the application icon in the task bar. Windows 7 does not do this. So if a Windows XP user only uses the application main form, no problems arise and both viewing modes work fine. If they open another window, the application icon appears, and stays there even after that window closes. Windows 7 does not do this, and the icon stays gone.
You should set
in your .dpr file and then never modify that setting.
Then, when you want to remove the main form from the taskbar you simply write
When you need to bring the main form out of hiding again write
And that’s it.
Naturally you’ll want to show and hide your notification area icon in concert with hiding and showing the main form.
The code in
HideWindowFromTaskbaris not necessary and you should remove it. When you application is inMainFormOnTaskBarequalsTruemode, the main form is an un-owned top-level window. And so it appears on the taskbar whenever it is visible. So you can remove the main form from the taskbar simply my hiding it.The other forms in your application will be owned top-level windows. Typically they will be owned by your main form. By virtue of being owner, they will not appear on the taskbar.
By and large you should try hard to avoid fiddling with window styles. You can usually make your application behave the way you need without doing so. What’s more, if ever you have to adjust window styles, you must do it in
CreateParams. That way the window style will persist when the window gets re-created. But I re-iterate, avoid modifying window styles where you can.The key MSDN references are:
Here’s the smallest program I can produce that proves the point:
In the comments you make it clear that you want to be able to hide the taskbar window without hiding the main form. In that case I suggest that you set
MainFormOnTaskbartoFalse. That will mean thatApplication.Handlewill be the window associated with the taskbar button. You can then hide that window to remove it from the taskbar.You will now need to explicitly set
PopupParentfor any auxiliary forms. If you want those windows to be owned by the main form, then you can set it up.Here’s my example adjusted for this scenario:
Run this program and click on the toggle button. Now you will see main form and other form showing. And nothing in the taskbar. I included the toggle button to show that you can switch between your two modes of operation whilst the program is running. No need to restart it.
The key here is to make a window other than your visible forms be the window associated with the taskbar. Once you do that you can once again control taskbar presence by showing and hiding that window. In this case that window is the application window,
Application.Handle. Because that’s the window on the taskbar, you need to set itsTitleproperty to control its text.I stress finally, once again, that interaction with the taskbar is best controlled with window owner and visibility. Always search for solutions using those methods rather than
ITaskbarList, extended window styles etc.Update
Hopefully the last word on the subject. As you have noticed, the code directly above has poor behaviour when the main form is minimised. When that happens, the application window is made visible again and so appears once more in the taskbar.
I’m not so sure of myself when it comes to suppressing this behaviour. The behaviour comes about because of the code in
TApplication.Minimizewhich shows the application handle when the main form is minimized. The best solution that I have is to convert a main form minimize into a hide.Or another way would be to suppress the application window show by means of an
OnMinimizeevent handler forTApplication.