hiding program in system tray

mirko_germany
mirko_germany used Ask the Experts™
on
hi,

is there a c/c++-function to hide a win32-console-program in the (is it called system tray?) lower right corner of the screen left of the clock? pls give me the name of the function, the syntax and an example. does the program run on, while it is hidden? can i popup it on any event (if(event()) (popup()); or something like that)?

thx in fwd

mirko
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
Do you mean show a program in the system tray?  They can hardly be called hidden if they're visible in the system tray, and since you need to go to extra effort to show a program in the tray, then you don't need to do anything to prevent a program from being shown in the tray.

Gary

Commented:
For tray icon manipulations (add/modify/delete) you must use Win32 API func Shell_NotifyIcon.
But! When you add the icon, any notifications from that icon Windows posted to main window procedure of your app. Because Win32-console app haven't window procedure, you can't handle these notifications.
I you want use systray icons, your app must be 'windowed', i.e. non-console.
There small sample of use Shell_NotifyIcon (from SDK):

The function in the following example demonstrates how to add an icon to the taskbar.

// MyTaskBarAddIcon - adds an icon to the taskbar notification area.
// Returns TRUE if successful or FALSE otherwise.
// hwnd - handle of the window to receive callback messages
// uID - identifier of the icon
// hicon - handle of the icon to add
// lpszTip - tooltip text
BOOL MyTaskBarAddIcon(HWND hwnd, UINT uID, HICON hicon, LPSTR lpszTip)
{
    BOOL res;
    NOTIFYICONDATA tnid;
 
    tnid.cbSize = sizeof(NOTIFYICONDATA);
    tnid.hWnd = hwnd;

    tnid.uID = uID;
    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    tnid.uCallbackMessage = MYWM_NOTIFYICON;
    tnid.hIcon = hicon;
    if (lpszTip)
        lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
    else
        tnid.szTip[0] = '\0';
 
    res = Shell_NotifyIcon(NIM_ADD, &tnid);
 
    if (hicon)
        DestroyIcon(hicon);
 
    return res;
}
 

To delete an icon from the taskbar notification area, you must fill a NOTIFYICONDATA structure and send it to the system in the context of an NIM_DELETE message. When deleting a taskbar icon, you need to specify only the cbSize, hWnd, and uID members, as the following example shows.

// MyTaskBarDeleteIcon - deletes an icon from the taskbar
//     notification area.
// Returns TRUE if successful or FALSE otherwise.
// hwnd - handle of the window that added the icon
// uID - identifier of the icon to delete
BOOL MyTaskBarDeleteIcon(HWND hwnd, UINT uID)
{
      BOOL res;
      NOTIFYICONDATA tnid;
 
      tnid.cbSize = sizeof(NOTIFYICONDATA);
      tnid.hWnd = hwnd;
      tnid.uID = uID;
             
      res = Shell_NotifyIcon(NIM_DELETE, &tnid);
      return res;

}

Hope this helps.

Author

Commented:
hi,

i don't want to add an icon to the taskbar, but my whole program. i want it like e.g. icq or kazaa does: u start the program in full screen mode or window mode, and if u minimize it (or if u enter 'min') it should by hidden - or shown, as u like - in the system tray. then, if there is an event - e.g. data is available on the network socket of the program, it should popup and show the user the available message.

i don't matter, what icon u can see in the taskbar that time. it could be this simple icon for windows-console-apps or dos-apps.

mirko
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

on min: add to tray - remove from taskbar
on max: remove from tray - add to taskbar
you still need to have a windows app, you need a window procedure to be able to get the messages from the system tray. you need a hwnd. cant do this in console and have it be functional.

Commented:
One way what i know to get your-own console window handle is:

char szTitle[] = TEXT("My console window");
SetConsoleTitle(szTitle);
// or
// char szTitle[200];
// GetConsoleTitle(szTitle, sizeof(szTitle));
HWND hwndConsole = FindWindow(NULL, szTitle);

When you have a window handle you can show or hide him by call of ShowWindow function:

ShowWindow(hwndConsole, SW_HIDE); // hide window
ShowWindow(hwndConsole, SW_SHOW); // show window

O.k. Now you know how you can show/hide your app. But another problem is what you can't handle "minimize" message (you haven't window proc).
Then you must watch self when window minimized (in some loop):

if (hwndConsole && IsIconic(hwndConsole))
{
    // window minimized
    if (MyTaskBarAddIcon(NULL, 0, hIcon, TEXT("Icon tip")))
        ShowWindow(hwndConsole, SW_HIDE);
}

In your event handler (when your app must popup):

if (!IsWindowVisible(hwndConsole))
{
    MyTaskBarDeleteIcon(NULL, 0);
    ShowWindow(hwndConsole, SW_SHOW);
}

That's all.

Author

Commented:
i've now written a test app that just shows the window, waits for keyboard input, hides it for 10 seconds and shows it again. i at first ran it without MyTaskBarAddIcon() and it hid, but didn't show an icon. then i copied ur functions MyTaskBar...Icon() of ur previous commend to the program, but now it gets errors:

Undefined symbol MYMW_NOTIFYICON
Undefined symbol hIcon

against the first error i put // at the beginning of the line - this solved the error message, but i don't know what this line is good for.
against the second one i put HICON hIcon; to the beginning of main(), but i think, there are some members of hIcon to be set!?

all in all it compiled and linked errorless then, but there was no icon in the tray.

here is my code:

// windows-console-app to hide in systray

#include <windows.h>
#include <iostream.h>
#include <conio.h>
#include <time.h>

BOOL MyTaskBarAddIcon(HWND hwnd, UINT uID, HICON hicon, LPSTR lpszTip)
{
    BOOL res;
    NOTIFYICONDATA tnid;

   tnid.cbSize = sizeof(NOTIFYICONDATA);
    tnid.hWnd = hwnd;

    tnid.uID = uID;
    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
//    tnid.uCallbackMessage = MYWM_NOTIFYICON;
    tnid.hIcon = hicon;
    if (lpszTip)
        lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
    else
        tnid.szTip[0] = '\0';

   res = Shell_NotifyIcon(NIM_ADD, &tnid);

   if (hicon)
        DestroyIcon(hicon);

   return res;
}

BOOL MyTaskBarDeleteIcon(HWND hwnd, UINT uID)
{
     BOOL res;
     NOTIFYICONDATA tnid;

    tnid.cbSize = sizeof(NOTIFYICONDATA);
     tnid.hWnd = hwnd;
     tnid.uID = uID;

    res = Shell_NotifyIcon(NIM_DELETE, &tnid);
     return res;

}

void main()
{
      char szTitle[] = TEXT("My console window");
      SetConsoleTitle(szTitle);
   HWND hwndConsole = FindWindow(NULL, szTitle);
   HICON hIcon;
   clock_t time;
      if (hwndConsole && IsIconic(hwndConsole))
      {
   // window minimized
         if (MyTaskBarAddIcon(NULL, 0, hIcon, TEXT("Icon tip")))
            ShowWindow(hwndConsole, SW_HIDE);
      }
   cout << "Window created! Press key to hide in systray...\n";
   getch();
   cout << "Window will be hidden! Wait...\n";
   ShowWindow(hwndConsole, SW_HIDE);
   cout << "Window is hidden!\n";
      time=clock();
   while((clock()-time)/CLOCKS_PER_SEC<10);
   if (!IsWindowVisible(hwndConsole))
      {
         MyTaskBarDeleteIcon(NULL, 0);
         ShowWindow(hwndConsole, SW_SHOW);
      }
   cout << "Window shown!\n";
   getch();
}

Author

Commented:
ps: res returns false

Commented:
MYMW_NOTIFYICON - message what posted to window procedure when trayicon event occurs. You don't need that.
hIcon - handle of icon to add to systray

This small program shows how i did that:

#include <windows.h>
#include <stdio.h>

BOOL MyTaskBarAddIcon(UINT uID, HICON hicon, LPSTR lpszTip)
{
    BOOL res;
    NOTIFYICONDATA tnid;
    ZeroMemory(&tnid, sizeof(NOTIFYICONDATA));
 
    tnid.cbSize = sizeof(NOTIFYICONDATA);
    tnid.uID = uID;
    tnid.uFlags = NIF_ICON | NIF_TIP;
    tnid.hIcon = hicon;

    if (lpszTip)
        lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
    else
        tnid.szTip[0] = '\0';
 
    res = Shell_NotifyIcon(NIM_ADD, &tnid);
 
    return res;
}

BOOL TaskBarDeleteIcon(UINT uID)
{
      BOOL res;
      NOTIFYICONDATA tnid;
      ZeroMemory(&tnid, sizeof(NOTIFYICONDATA));
 
      tnid.cbSize = sizeof(NOTIFYICONDATA);
      tnid.uID = uID;
             
      res = Shell_NotifyIcon(NIM_DELETE, &tnid);

      return res;
}

void main()
{
      // i wait second while window created
      Sleep(1000);

      char szTitle[200];

      GetConsoleTitle(szTitle, sizeof(szTitle));

      HWND hwndConsole = FindWindow(NULL, szTitle);

      if (!hwndConsole)
      {
            puts("Console window not found");
            return;
      }

      // load standard windows icon
      HICON hIcon = LoadIcon(NULL, IDI_WINLOGO);

      puts("Press Enter to hide window on 5 seconds");
      getchar();

      // add icon 2 systray & hide window
      if (MyTaskBarAddIcon(0, hIcon, TEXT("Tray icon tip")))
      {
            ShowWindow(hwndConsole, SW_HIDE);
      }
      else
      {
            puts("MyTaskBarAddIcon failed");
            return;
      }

      // wait 5 seconds
      Sleep(5000);

      // restore window & remove icon
      ShowWindow(hwndConsole, SW_SHOW);
      TaskBarDeleteIcon(0);

      puts("Show/hide window test succesfull\n");
      puts("Press Enter to quit...");
      getchar();
}

Hope this sample is complete :)
mirko you do realize that without a window proc your icon will have no functionality
you wont recieve messages from the system tray so all you will be able to do is put an icon there and then you have to tell it when to show again, the user will have no choice in that.

Author

Commented:
i now filled in the LoadIcon() and deleted the IsIconic(). what about this last function? it seams to return false, and so my program wasn't hidden. is this function nessecary?

now the icon is placed in the tray very fine, but the next problem that occured was, that if i move the mouse cursor to the icon the icon suddenly dissappears (i didn't believe in ghosts bevor ;-) ), like other icons do, if the programs that belong to the icon had hang. but i wish the icon to make my window shown if i click on the icon, if that is possible.

but i have to say that i'm very glad about what u wrote till now.

thx

mirko
Commented:
From Win32 SDK:

The IsIconic function determines whether the specified window is minimized (iconic).

BOOL IsIconic(
    HWND  hWnd       // handle of window
);

> but i wish the icon to make my window shown if i click on the icon, if that is possible
It's impossible for console app. I wrote before what any notifications (clicks, mouse move) from icon windows send to window procedure. Console app haven't wndproc, then can't handle notifycations from icon.
If you want add to your program "hide-to-tray" functionality, you must write normal (windowed) app, but not console.

Author

Commented:
hi,

hiding programs in background works so far for windows console apps. now i've also learned how to program dialog based win32-gui-apps and so i would like to know, how i can do it here. i increased the points from 100 to 150 for that.

i now wrote a simple program with borland c++ builder 5, which shows a dialog with a button 'minimize'. when i klick on it, the program should be minimized, every five seconds it should be maximized. here is the code of the unit1.cpp:

// This was automatically generated:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

// These both are the functions of avdey from 09/01/03
BOOL MyTaskBarAddIcon(UINT uID, HICON hicon, LPSTR lpszTip)
{
    BOOL res;
    NOTIFYICONDATA tnid;
   ZeroMemory(&tnid, sizeof(NOTIFYICONDATA));

    tnid.cbSize = sizeof(NOTIFYICONDATA);
   tnid.uID = uID;
   tnid.uFlags = NIF_ICON | NIF_TIP;
   tnid.hIcon = hicon;

   if (lpszTip)
        lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
    else
        tnid.szTip[0] = '\0';

   res = Shell_NotifyIcon(NIM_ADD, &tnid);

   return res;
}

BOOL TaskBarDeleteIcon(UINT uID)
{
     BOOL res;
     NOTIFYICONDATA tnid;
    ZeroMemory(&tnid, sizeof(NOTIFYICONDATA));

     tnid.cbSize = sizeof(NOTIFYICONDATA);
     tnid.uID = uID;

    res = Shell_NotifyIcon(NIM_DELETE, &tnid);

     return res;
}

// This function is the one, which is called, if the user clickes on 'minimize':
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   char szTitle[200];
   GetConsoleTitle(szTitle, sizeof(szTitle)); // i think this must be another command, as it is called ...Console...?
   HWND hwndConsole = FindWindow(NULL, szTitle);
   if (!hwndConsole)
   {
      MessageBox(NULL,"Console window not found!","Error while hiding",0); // this error is prompted to me
      return;
   }
   // load standard windows icon
   HICON hIcon = LoadIcon(NULL, IDI_WINLOGO);

   // add icon 2 systray & hide window
   if (MyTaskBarAddIcon(0, hIcon, TEXT("Tray icon tip")))
   {
      ShowWindow(hwndConsole, SW_HIDE);
   }
   else
   {
      MessageBox(NULL, "MyTaskBarAddIcon failed!","Error while hiding",0); // this error is prompted, if i delete the 'return' after the first error
      return;
   }
}
//---------------------------------------------------------------------------

// this function is called every five seconds by a timer:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
   char szTitle[200];
   GetConsoleTitle(szTitle, sizeof(szTitle)); // again this ...Console...
   HWND hwndConsole = FindWindow(NULL, szTitle);
   if (!hwndConsole)
   {
      MessageBox(NULL,"Console window not found!","Error while showing",0); // this error occurs!
      return;
   }
   ShowWindow(hwndConsole, SW_SHOW);
   TaskBarDeleteIcon(0);
}
//---------------------------------------------------------------------------

at this moment there is now icon added and the program doesn't minimize.

would be pleased for further help

mirko
you can have a console in any program and so can also have a window proc -> systray icon
Can you not have a window in your console app? Do calls to createwindow fail?

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial