Click here to Skip to main content
15,892,005 members
Articles / Desktop Programming / MFC
Article

SDI/MDI MFC application in the Windows System Tray

Rate me:
Please Sign up or sign in to vote.
4.91/5 (26 votes)
11 Mar 20033 min read 182.1K   3.7K   61   29
This article describes the process of creating an application that is startup-hidden and is opened when clicking on the system tray icon. The SDI VC++ v6.0 demo project is attached. The project demonstrates the use of a hidden window, a system tray icon and a startup flipping prevention technique.

Overview

This article describes the process of creating an application that is startup-hidden and is opened when clicking on the system tray icon. The SDI VC++ v6.0 demo project is attached. The project demonstrates the use of a hidden window, a system tray icon and a startup flipping prevention technique.

Introduction

The right part of the Windows Task Bar is the system tray. It includes icons of hidden applications such as the system clock dialog, the sound volume dialog, some antivirus programs etc.

I created a SDI MFC project to demonstrate the technique of creating such an application. Why SDI? I needed an application with a graphic output (see link). Dialog based applications could be created the same way. It is easier because dialog applications don't have the flipping problem that is described below.

Icon control

Do you want to put in the system tray an icon of your program? No problem. SDK Shell_NotifyIcon function lets you put, remove or change an icon in the system tray. I created a method CMainFrame::TrayMessage( DWORD dwMessage) for convenient use of this function. The dwMessage parameter defines what we need to do with the system tray icon.

BOOL CMainFrame::TrayMessage( DWORD dwMessage)
{

    CString sTip(_T("BrigSoft Example")); 
    NOTIFYICONDATA 
    tnd;
    tnd.cbSize = sizeof(NOTIFYICONDATA);
    tnd.hWnd = m_hWnd;
    tnd.uID = IDR_TRAYICON;
    tnd.uFlags = NIF_MESSAGE|NIF_ICON;
    tnd.uCallbackMessage = MYWM_NOTIFYICON;
    tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; 
    VERIFY( 
        tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), 
                        MAKEINTRESOURCE (IDR_TRAYICON)) 
    );
    lstrcpyn(tnd.szTip, (LPCTSTR)sTip, sizeof(tnd.szTip));

    return Shell_NotifyIcon(dwMessage, &tnd);

}

I call TrayMessage(NIM_ADD) from CMainFrame::OnCreate. It shows an icon after the program is started. Calling TrayMessage( NIM_DELETE ) from CMainFrame::OnClose removes the icon when application is finished.

You can easily change this function to use the NIM_MODIFY message, if you want to change the icon or the tooltip.

Show and hide the main window

Shell_NotifyIcon function receives NOTIFYICONDATA structure. It includes a handle of a window and a window message number. If some event takes place on the icon, the system tray sends the message to the window.

I defined user message MYWM_NOTIFYICON for this purpose.

#define MYWM_NOTIFYICON (WM_USER+2)

To receive this message I overloaded the virtual function WindowProc (using MFC Wizard).

LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    // Open window when double click to the Systray Icon
    if(message == MYWM_NOTIFYICON){ 
        switch (lParam){

            case WM_LBUTTONDBLCLK: 
                switch (wParam) {

                    case IDR_TRAYICON:

                        ShowWindow(SW_NORMAL);
                        SetForegroundWindow();
                        SetFocus();
                        return TRUE; 
                        break; 
                } 
                break; 
        } 
    } 
    return CFrameWnd::WindowProc(message, wParam, lParam);

}

I catch only the WM_LBUTTONDBLCLK message. Other mouse messages can be caught too. After the WM_LBUTTONDBLCLK occur, I open the window using ShowWindow(SW_NORMAL).

Most of the system tray programs hide their main window instead of minimizing it. To do so I use OnSize message handle in such a way:

void CMainFrame::OnSize(UINT nType, int cx, int cy) 
{
     if(nType == SIZE_MINIMIZED){
          ShowWindow(SW_HIDE);
     }
     else{
          CFrameWnd::OnSize(nType, cx, cy); 
     } 
}

Hide on start

MFC SDI/MDI projects show the main applications window immediately after the start. If you want to start an application in a hidden mode, you must change InitInstanse() function of the App class. Change the strings:

     m_pMainWnd->ShowWindow(SW_SHOW);
     m_pMainWnd->UpdateWindow();

to

     m_pMainWnd->ShowWindow(SW_HIDE);

The application will start as hidden but you will see a flipping window. It opens and immediately closes. The problem occurs in Microsoft's CDocTemplate class. There is only one solution: to overload CSingleDocTemplate (CMultiDocTemplate) class. I created BsDocTemplate class (child of CSingleDocTemplate) to fix this problem. Microsoft can solve this problem easier:

by changing

virtual CDocument* OpenDocumentFile(LPCTSTR lpszPathName, 
                                   BOOL bMakeVisible = TRUE);

to

virtual CDocument* OpenDocumentFile(LPCTSTR lpszPathName, 
                                   BOOL bMakeVisible = FALSE);

in the CDocTemplate class definition. But they have not fixed it yet.

Demo project

MFCStartUp demo project is a SDI MFC application. It hides while you start it. So you will see no window after the start, only a small green icon in the system tray. To open the application, double click this icon. To hide the application, click the minimize button of the main window.

Links

The technique described in this article is used in the project Activity Counter.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Question#if way? Pin
Super Garrison6-Aug-08 7:10
Super Garrison6-Aug-08 7:10 
Questionanyone know how to add in pop up menu if we right click the icon tray??? Pin
warr~~en25-Jun-08 22:14
warr~~en25-Jun-08 22:14 
Questionhelp needed! Pin
abc_nus_student22-Nov-07 23:24
abc_nus_student22-Nov-07 23:24 
Generalhi ,help me plz ........................... Pin
ntsol20-Sep-07 22:28
ntsol20-Sep-07 22:28 
GeneralFlipping window prevention, even very simple [modified] Pin
Wichen Moormann27-Jun-07 2:24
Wichen Moormann27-Jun-07 2:24 
SorryCry | :(( I was trapped in the code and didn’t see the wood for the trees.
As more I became involved, I debugged around, and suddenly things became quite simple.
Here is the solution for the flipping window problem, when hiding the main window on start:

First of all forget the BsDocTemplate Class completely, you don’t need it.
Keep the standard DocTemplate Class.
Secondly this problem occurs only in the standard SDI application, not in the standard MDI application.

The standard call sequence in CMyProgWinApp::InitInstance() is:
//--------------------------------
ProcessShellCommand(cmdInfo);
m_pMainWnd->ShowWindow(SW_SHOW);
//--------------------------------

To hide the Window, one would try:
//--------------------------------
ProcessShellCommand(cmdInfo);
m_pMainWnd->ShowWindow(SW_HIDE);
//--------------------------------
The application will start as hidden but you will see a flipping window. It opens and immediately closes.

The reason is the following:
All MFC applications set CWinApp::m_nCmdShow = SW_SHOWNORMAL ( = 1) before calling CMyProgWinApp::InitInstance().
In the standard SDI application the main window is constructed with ProcessShellCommand(cmdInfo) and is so already visible without any call m_pMainWnd->ShowWindow(SW_SHOW) !!! (You can demonstrate this by simply commenting: //m_pMainWnd->ShowWindow(SW_SHOW); )
If you then follow with the call m_pMainWnd->ShowWindow(SW_HIDE), you see a flipping window.

To prevent the flipping window you have to set m_nCmdShow = SW_HIDE
before the call ProcessShellCommand(cmdInfo).
This will construct the main window unvisible.
You even don't need the call m_pMainWnd->ShowWindow(SW_HIDE) !!!
Thus all is done with:Cool | :cool:
//--------------------------------
m_nCmdShow = SW_HIDE;
ProcessShellCommand(cmdInfo);
--------------------------------
The calls m_pMainWnd->ShowWindow(...) are redundant here.
And this is where Bill Gates comes in: He earns money with selling redundant stuff. Apparently we like redundant stuff and so he is the richest man of the world.

Servus from Munich

Wichen
wmoormann@ampacs.de

-- modified at 8:57 Wednesday 27th June, 2007

brucetp (see below: This may interest you ..., 14 Jan 2004) was already on the way. But he didn't get the point that in the SDI App the Window shows up with the call ProcessShellCommand(cmdInfo);
GeneralRe: Flipping window prevention, even very simple Pin
Ganesh7931-Oct-07 19:48
Ganesh7931-Oct-07 19:48 
GeneralRe: Flipping window prevention, even very simple Pin
Hitesh Sharma13-Jan-08 18:29
Hitesh Sharma13-Jan-08 18:29 
GeneralRe: Flipping window prevention, even very simple Pin
vikrant kpr30-Nov-08 8:33
vikrant kpr30-Nov-08 8:33 
GeneralRe: Flipping window prevention, even very simple Pin
JCusma26-May-09 7:03
JCusma26-May-09 7:03 
GeneralFlipping window solution BsDocTemplate, simple code [modified] Pin
Wichen Moormann11-Jun-07 0:15
Wichen Moormann11-Jun-07 0:15 
Questionrasdial tray icon Pin
Brilliant Star29-May-07 4:36
Brilliant Star29-May-07 4:36 
GeneralThis is tray for SDI/MDI but i want for dailog Pin
ashu_om19-Apr-07 0:22
ashu_om19-Apr-07 0:22 
Generalhide the icon of another process than the mine Pin
NewMan45646412-May-05 20:35
sussNewMan45646412-May-05 20:35 
Questionhow to get the handle of icons displayed in system tray Pin
narasimhavarmap12-Apr-05 19:54
narasimhavarmap12-Apr-05 19:54 
GeneralHelp me Pin
sionie5-May-04 7:10
sionie5-May-04 7:10 
GeneralHIDE ON START, BUT DIALOG BASED MFC APP Pin
andresfecas3-Apr-04 3:49
andresfecas3-Apr-04 3:49 
GeneralRe: HIDE ON START, BUT DIALOG BASED MFC APP Pin
Brigsoft3-Apr-04 21:15
Brigsoft3-Apr-04 21:15 
GeneralRe: HIDE ON START, BUT DIALOG BASED MFC APP Pin
matasko7-Nov-04 8:01
matasko7-Nov-04 8:01 
GeneralRe: HIDE ON START, BUT DIALOG BASED MFC APP Pin
maddyMathan21-Nov-06 17:12
maddyMathan21-Nov-06 17:12 
GeneralRe: HIDE ON START, BUT DIALOG BASED MFC APP Pin
maddyMathan21-Nov-06 23:43
maddyMathan21-Nov-06 23:43 
AnswerRe: HIDE ON START, BUT DIALOG BASED MFC APP Pin
shritiParashars4-Jan-07 20:01
shritiParashars4-Jan-07 20:01 
AnswerRe: HIDE ON START, BUT DIALOG BASED MFC APP Pin
shritiParashars4-Jan-07 20:12
shritiParashars4-Jan-07 20:12 
GeneralThis may interest you.... Pin
brucetp14-Jan-04 5:03
brucetp14-Jan-04 5:03 
GeneralOnInitialUpdate Pin
deafpat13-Jan-04 21:35
deafpat13-Jan-04 21:35 
GeneralRe: OnInitialUpdate Pin
Hawks20-Nov-04 1:26
Hawks20-Nov-04 1:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.