Link to home
Start Free TrialLog in
Avatar of ZhaawZ
ZhaawZFlag for Latvia

asked on

hiding app from taskbar; forms` icons in alt+tab window

I have an application that runs in background (it's minimized almost all the time). I need to hide it from taskbar:
with Application do SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);

So what's the problem. As I said - application is minimized almost all the time and is not visible. But when I show some window from this application (ToolWindow, if it matters; there are several windows - ToolWindows and windows without caption, just with sizeable border), application (small box with appliction`s caption, 'restore', 'maximize' and 'exit' buttons) appears in the left down corner of display. How to avoid this appearing?

One more problem - when I press alt+tab, there are several icons for this application (one icon for each form; forms do not have caption, if it matters). When some ToolWindow (a form with BorderStyle set to bsToolWindow) is visible, there are no icons at all for this app. How to do so that there's one and only one icon for application, when I press alt+tab (no matter - is any of application`s windows visible or not, is application minimised or not)?

Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

Whenever I need to create applications that have to run in the background, I tend to divide them into two parts. First the background task that becomes a service application. (File/New/Other/Service Application) Put all the code in it that you need to run in the background and add some code for some communication protocol. A TCP/IP server component from Indy would be just fine, bt a simple named pipe could run perfectly too.
The second application would be the configuration tool. This could be a normal application but if you want to be real cool, make it a control applet. (File/New/Other/Control Panel Application) This second application will have to communicate with the service through the communication protocol that you've chosen and could be closed whenever you're done with it.

The advantage of this technique is that your application will keep on running and it will only show up in the task manager and nowhere else. Not even with Alt+Tab. But the second application could even be used to configure your main application from another computer, if you'd like that.

The disadvantage is that this technique is pretty complex at first and quite difficult to debug. The service itself will require Windows NT as a minimum and won't run on Windows 95/98 or ME. But hey, it's just a suggestion since it could be a useful and different approach.
Avatar of ZhaawZ

ASKER

I'm not able to create Service Application because there's no such 'file --> new --> other --> service application' (I'm using Delphi 6 Personal).
I also need to make an app that will run on both WinNT and Win9x systems.
minimize it to system tray (if this is not a problem)
Avatar of ZhaawZ

ASKER

Yes, there's an icon for an app in try. I also minimize and restore application with this icon.
Restoring:    SendMessage(msg.WParam, WM_SYSCOMMAND, SC_RESTORE, 0);
Minimizing:    SendMessage(msg.WParam, WM_SYSCOMMAND, SC_MINIMIZE, 0);'

The first problem was:
When application is minimized and some window becomes visible (so an application is now minimized, some tool window - visible), there appears a small box with appliction`s caption and 'restore', 'maximize' and 'exit' buttons (I suppose this is minimized window of an application, not a form). I need to do so that this "box" does not appear.
try with Application.Minimize instead of send message...
Avatar of ZhaawZ

ASKER

Doesn't work also with application.minimize.
This problem is now solved - I use ShowWindow(Application.Handle, SW_SHOW) before restoring and ShowWindow(Application.Handle, SW_HIDE) after minimizing.


There are two more problems.


First one (I already wrote about it) - icons in "alt+tab window":
* when application is in normal state (not minimized, without any visible toolwindow), there are one icon for each application`s visible form. For example - if there are 6 visible forms, there are also 6 icons in "alt+tab window".
* when application is not minimized, but there is some toolwindow visible (I use ShowModal to show these toolwindows), there are no icons in "alt+tab window" at all for this application.
* when application is minimized (whether any toolwindow is visible or not), there are no icons in "alt+tab window" at all for this application.
In all of these 3 cases there must be one and only one icon for this application in "alt+tab window".


Second problem (was not mentioned above) - minimizing/restoring/activating an application when clicking on icon in tray.
There's no problem to minimize/restore an application.

procedure TrayIconClick  (var msg : TMessage); message 9753;

procedure TMainForm.TrayIconClick(var msg : TMessage);
const
  tray_button_left_up       : word = 514;
var
  info : WINDOWPLACEMENT;
begin
if msg.LParam = tray_button_left_up then begin
  info.length := SizeOf(info);
  GetWindowPlacement(msg.WParam, @info);
  if (info.showCmd = SW_SHOWMINIMIZED) or (info.showCmd = SW_SHOWMINNOACTIVE) then begin
    ShowWindow(msg.WParam, SW_SHOW);
    SendMessage(msg.WParam, WM_SYSCOMMAND, SC_RESTORE, 0);
  end else begin
    SendMessage(msg.WParam, WM_SYSCOMMAND, SC_MINIMIZE, 0);
    ShowWindow(msg.WParam, SW_HIDE);    
  end;
end;
end;

9753 is a message that a form gets when user clicks or moves a mouse cursor over the icon in tray.
msg.LParam is "action" that user does with icon in tray (in this case there's only 514 - releasing left mouse button).
msg.WParam in this case is a handle to an application (can be also a handle to a form - it doesn't matter this time).

That procedure above only minimizes/restores application. I need to do so that if an application is not active when user clicks on icon in tray, it becomes active (not minimizes). It could be done by using GetForegroundWindow to check if application is active, but there's some problem - when I click on icon in tray, the form (application) is not active anymore. How can I check if it was active before clicking on icon in tray?

About ALT + TAB ... It doesn't catch Dialog windows.

Why not using .BringToFront method, combined with SetForegroundWindow ?
Avatar of ZhaawZ

ASKER

How can I checkt with BringToForm which was the last active window?
BringToFront works only within the application.

About "alt+tab window". It shows one icon (for application, not each form) if there's a visible button for application in taskbar, whether there is some tool window visible or not, whether an application is minimized or not. When I hide this button, it goes totally wrong with these icons.
Maybe there's some other way to hide it from taskbar than this?
with Application do SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
Avatar of krypto2000
krypto2000

I've a solution for the minimize event that can hide the application from the taskbar and the ALT+TAB menu

//------------------------------------------------------//
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure minimizeApp(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.minimizeApp(Sender: TObject);
begin
   self.Visible := false;
// make the tray icon visible and more...
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   Application.OnMinimize := minimizeApp;
end;
//------------------------------------------------------//

but i think the best way for u is to make a windows NT services, and after you make a control panel applet for configuring your services parameters,
if you want some example just say...
Avatar of ZhaawZ

ASKER

krypto2000:
  As I already said - I need one icon for application in "alt+tab window". Read my comments if you didn't understand what excatly I need.
  I also said that I can't make windows nt service.
okay sorry i'm not english i'm swiss so I make that I can to help some people but something I don't understand exactly...
I had exactly the same problem that you did for one of these problems and found a slightly more elegant solution I think.

The reason that whenever you make a form visible the application taskbar icon appears...
In the constructor for TCustomForm the function Screen.AddForm(Self) is called.  This updates Screen.Forms and Screen.CustomForms.
Whenever a form changes visibility the Application.UpdateVisible procedure is called.  This looks through Screen.Forms for any visible forms and sets the application window visible (hence the taskbar button visible) if any are found.

However if you make your forms descend from something other than TForm then you can avoid this.  I use a new class called TDesktopForm = class(TCustomForm) then change my class definitions to inherit from that instead of from TForm.  If you look at the definition of TForm it doesn't do much over and above what TCustomForm does anyway, mainly it just exposes a set of properties, which you can do in your TDesktopForm class too.

I have not used the TOOLWINDOW style myself - it seems to remove windows from the alt+tab list (amongst other things).

I think that if you try modifying the inheritance in the way I suggest then you won't need to use TOOLWINDOW and you'll get no taskbar buttons.  In my tests this system left one and only one icon in the alt+tab list, which is what you wanted I think?  The only other thing is that you'll probably want to disable the minimize button as it behaves strangely - users probably only want the close button from what I understand of your requirements.
if I want to hide my application I just use this simple code in the dpr source

Application.ShowMainForm:=false;

which looks like.
{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.ShowMainForm:=false;
  Application.Run;
end.

so my app doesn't show, and it will never show unless I call form1.show; which I wont call cos I don't want it to be shown
Avatar of ZhaawZ

ASKER

SaLz, this doesn't work for me. I need a form to be visible when user clicks on an icon in tray. I use ShowWindow() with SW_SHOW parameter to show a form. If I set ShowMainForm to false, then most of controls on form aren't painted, when a form gets visible (maybe they even aren't created, I don't know actually; do I have to paint/create them manually now?).

I solved this problem by calling ShowWindow with sw_hide parameter in onPaint event when form is painted first time (form`s flashing when application starts, but it`s ok for me this time).

btw, one more thing - sometimes form must be shown when application starts - it depend's on some operations which are done/aren`t done when form is created.



About the problem I mentioned @ 10/19/2004 09:46PM EEST ("minimizing/restoring/activating an application when clicking on icon in tray", actually it's hiding/restoring/showing a window) - I also solved this problem. The problem was that when user clicks on icon in tray, form loses a focus (if it has one), so there's no possibility to check if form is active or not (to know, what to do next - to activate form (if it wasn't active) or to hide it (if it was active)). Procedure 'proc' finds last active visible window and sets it as foreground window.

procedure TMainForm.TrayIconMessages;

  function proc(wnd : cardinal; param : integer) : boolean; stdcall;
  begin
  if IsWindowVisible(wnd) then begin
    if wnd = FindWindow('Shell_TrayWnd', nil) then begin
      proc := true;
    end else begin
      SetForegroundWindow(wnd);
      proc := false;
    end;
  end else proc := true;
  end;

begin                    
case msg.HitTestCode of
  514 : begin              
          if IsWindowVisible(handle) then begin
            EnumWindows(@proc, 0);
            if GetForegroundWindow = handle then begin
              ShowWindow(handle, sw_hide);
            end else begin
              SetForegroundWindow(handle);
            end;
          end else begin
            ShowWindow(handle, sw_show);
            SetForegroundWindow(handle);
          end;
        end;
end;
end;
ASKER CERTIFIED SOLUTION
Avatar of ee_ai_construct
ee_ai_construct
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial