dcsimg

SDI/MDI MFC Application in the Windows System Tray

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


Environment: VC6, VC7, Windows 9x/NT/2000/XP

Overview

This article describes the process of creating an application that is startup-hidden and is opened when the user clicks the System Tray icon. The SDI VC++ v6.0 demo project is included. The project demonstrates the use of a hidden window, a System Tray icon, and a startup flipping prevent 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, and so forth.

I created an SDI/MFC project to demonstrate the technique of creating such an application. Why SDI? I needed an application with a graphic output (see http://www.brigsoft.com/bsactivity). A dialog-based application 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 an icon of your program in the System Tray? No problem. The SDK Shell_NotifyIcon function lets you put, remove, or change an icon in the System Tray. I created a CMainFrame::TrayMessage(DWORD dwMessage) method for the 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 the 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

The Shell_NotifyIcon function receives the 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 the user double-clicks 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 occurred, I open the window by using ShowWindow(SW_NORMAL).

Most of the System Tray programs hide their main window instead of minimizing it. To do so, I use the OnSize message handle in this manner:

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 they start. If you want to start an application in a hidden mode, you must change the 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 the CSingleDocTemplate (CMultiDocTemplate) class. I created the 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

The MFCStartUp demo project is a SDI/MFC application. It hides while you start it. So, you will see no windows 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, http://www.brigsoft.com/bsactivity.

© Alex Rest, 2003

Downloads

Download source - 22 Kb


Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date