Figure 1 CTrayIcon
 ////////////////////////////////////////////////////////////////
// TRAYTEST 1996 Microsoft Systems Journal. 
// See TRAYTEST.CPP for description of program.
// 
#include "resource.h"
class CMyApp : public CWinApp {
public:
   virtual BOOL InitInstance();
   //{{AFX_MSG(CMyApp)
   afx_msg void OnAppAbout();
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};TRAYTEST.CPP
 ////////////////////////////////////////////////////////////////
// TRAYTEST 1996 Microsoft Systems Journal. 
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// TRAYTEST illustrates how to use CTrayIcon. 
// All the activity takes place in MainFrm.cpp.
#include "stdafx.h"
#include "TrayTest.h"
#include "mainfrm.h"
CMyApp theApp;
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
   //{{AFX_MSG_MAP(CMyApp)
   ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CMyApp::InitInstance()
{
   // Create main frame window (don't use doc/view stuff)
   // 
   CMainFrame* pMainFrame = new CMainFrame;
   if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
      return FALSE;
   pMainFrame->ShowWindow(SW_HIDE);
   pMainFrame->UpdateWindow();
   m_pMainWnd = pMainFrame;
   OnAppAbout();
   return TRUE;
}
void CMyApp::OnAppAbout()
{
   CDialog(IDD_ABOUTBOX).DoModal();
}MAINFRM.H
 #include "trayicon.h"
//////////////////
// Main frame for TRAYTEST.
//
class CMainFrame : public CFrameWnd {
public:
   CMainFrame();
   virtual ~CMainFrame();
protected:
   DECLARE_DYNAMIC(CMainFrame)
   CStatusBar  m_wndStatusBar;
   CTrayIcon   m_trayIcon;    // my tray icon
   CEdit       m_wndEdit;     // to display tray notifications
   int         m_iWhichIcon;  // 0/1 which HICON to use
   BOOL        m_bShutdown;   // OK to terminate TRAYTEST
   BOOL        m_bShowTrayNotifications;  // display info in main window
   //{{AFX_MSG(CMainFrame)
   afx_msg LRESULT OnTrayNotification(WPARAM wp, LPARAM lp);
   afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
   afx_msg void OnToggleIcon();
   afx_msg void OnViewClear();
   afx_msg void OnViewNotifications();
   afx_msg void OnUpdateViewClear(CCmdUI* pCmdUI);
   afx_msg void OnUpdateViewNotifications(CCmdUI* pCmdUI);
   afx_msg void OnClose();
   afx_msg void OnAppOpen();
   afx_msg void OnAppSuspend();
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};MAINFRM.CPP
 ////////////////////////////////////////////////////////////////
// Main frame window implementation
//
#include "stdafx.h"
#include "TrayTest.h"
#include "mainfrm.h"
// Message ID used for tray notifications
#define WM_MY_TRAY_NOTIFICATION WM_USER+0
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   //{{AFX_MSG_MAP(CMainFrame)
   ON_MESSAGE(WM_MY_TRAY_NOTIFICATION, OnTrayNotification)
   ON_WM_CREATE()
   ON_COMMAND(ID_VIEW_CLEAR,           OnViewClear)
   ON_COMMAND(ID_TOGGLE_ICON,          OnToggleIcon)
   ON_COMMAND(ID_VIEW_NOTIFICATIONS,   OnViewNotifications)
   ON_UPDATE_COMMAND_UI(ID_VIEW_CLEAR, OnUpdateViewClear)
   ON_UPDATE_COMMAND_UI(ID_VIEW_NOTIFICATIONS, OnUpdateViewNotifications)
   ON_WM_CLOSE()
   ON_COMMAND(ID_APP_OPEN, OnAppOpen)
   ON_COMMAND(ID_APP_SUSPEND, OnAppSuspend)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
static UINT BASED_CODE indicators[] = {
   ID_SEPARATOR,           // status line indicator
};
CMainFrame::CMainFrame() : m_trayIcon(IDR_TRAYICON)
{
   m_bShowTrayNotifications = TRUE;
   m_bShutdown = FALSE;
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
      return -1;
   if (!m_wndStatusBar.Create(this) ||
      !m_wndStatusBar.SetIndicators(indicators, 
      sizeof(indicators)/sizeof(UINT))) 
      return -1;      // fail to create
   // Create child edit control for displaying messages
   CRect rc;
   if (!m_wndEdit.Create(
      WS_VISIBLE|WS_CHILD|WS_VSCROLL|ES_MULTILINE|ES_READONLY, rc, this, 
      AFX_IDW_PANE_FIRST))
      return -1;
   // Set up tray icon
   m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION);
   m_iWhichIcon = 1;
   m_trayIcon.SetIcon(IDI_MYICON);
   return 0;
}
//////////////////
// Close window. Unless we are shutting down, just hide it.
//
void CMainFrame::OnClose() 
{
   if (m_bShutdown)
      CFrameWnd::OnClose();
   else
      ShowWindow(SW_HIDE);
}
//////////////////
// Handle notification from tray icon: display a message.
//
LRESULT CMainFrame::OnTrayNotification(WPARAM uID, LPARAM lEvent)
{
   if (m_bShowTrayNotifications) {
      static LPCSTR MouseMessages[] = { "WM_MOUSEMOVE",
         "WM_LBUTTONDOWN", "WM_LBUTTONUP", "WM_LBUTTONDBLCLK",
         "WM_RBUTTONDOWN", "WM_RBUTTONUP", "WM_RBUTTONDBLCLK",
         "WM_MBUTTONDOWN", "WM_MBUTTONUP", "WM_MBUTTONDBLCLK" };
      CString s;
      s.Format("Tray notification: ID=%d, lEvent=0x%04x %s\r\n", 
         uID, lEvent, WM_MOUSEFIRST<=lEvent && lEvent<=WM_MOUSELAST ? 
         MouseMessages[lEvent-WM_MOUSEFIRST] : "(Unknown)");
      m_wndEdit.SetSel(-1, -1);     // end of edit text
      m_wndEdit.ReplaceSel(s);      // append string..
      m_wndEdit.SendMessage(EM_SCROLLCARET); // ..and make visible
   }
   // let tray icon do default stuff
   return m_trayIcon.OnTrayNotification(uID, lEvent);
}
////////////////////////////////////////////////////////////////
// Command handlers below.
//
void CMainFrame::OnViewClear() 
{
   m_wndEdit.SetWindowText("");  
}
void CMainFrame::OnUpdateViewClear(CCmdUI* pCmdUI) 
{
   pCmdUI->Enable(m_wndEdit.GetLineCount() > 1 || m_wndEdit.LineLength() > 0);
}
void CMainFrame::OnToggleIcon() 
{
   m_iWhichIcon=!m_iWhichIcon;
   m_trayIcon.SetIcon(m_iWhichIcon ? IDI_MYICON : IDI_MYICON2);
}
void CMainFrame::OnViewNotifications() 
{
   m_bShowTrayNotifications = !m_bShowTrayNotifications;
}
void CMainFrame::OnUpdateViewNotifications(CCmdUI* pCmdUI) 
{
   pCmdUI->SetCheck(m_bShowTrayNotifications);
}
void CMainFrame::OnAppOpen() 
{
   ShowWindow(SW_NORMAL);  
   SetForegroundWindow();
}
void CMainFrame::OnAppSuspend() 
{
   m_bShutdown = TRUE;     // really exit
   SendMessage(WM_CLOSE);  
}
TRAYICON.H
 ////////////////////////////////////////////////////////////////
// CTrayIcon Copyright 1996 Microsoft Systems Journal.
//
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
#ifndef _TRAYICON_H
#define _TRAYICON_H
////////////////
// CTrayIcon manages an icon in the Windows 95 system tray. 
// 
class CTrayIcon : public CCmdTarget {
protected:
   DECLARE_DYNAMIC(CTrayIcon)
   NOTIFYICONDATA m_nid;         // struct for Shell_NotifyIcon args
public:
   CTrayIcon(UINT uID);
   ~CTrayIcon();
   // Call this to receive tray notifications
   void SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg);
   // SetIcon functions. To remove icon, call SetIcon(0)
   //
   BOOL SetIcon(UINT uID); // main variant you want to use
   BOOL SetIcon(HICON hicon, LPCSTR lpTip);
   BOOL SetIcon(LPCTSTR lpResName, LPCSTR lpTip)
      { return SetIcon(lpResName ? 
         AfxGetApp()->LoadIcon(lpResName) : NULL, lpTip); }
   BOOL SetStandardIcon(LPCTSTR lpszIconName, LPCSTR lpTip)
      { return SetIcon(::LoadIcon(NULL, lpszIconName), lpTip); }
   virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent);
};
#endifTRAYICON.CPP
 ////////////////////////////////////////////////////////////////
// CTrayIcon Copyright 1996 Microsoft Systems Journal.
//
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
#include "stdafx.h"
#include "trayicon.h"
#include <afxpriv.h>    // for AfxLoadString
IMPLEMENT_DYNAMIC(CTrayIcon, CCmdTarget)
CTrayIcon::CTrayIcon(UINT uID)
{
   // Initialize NOTIFYICONDATA
   memset(&m_nid, 0 , sizeof(m_nid));
   m_nid.cbSize = sizeof(m_nid);
   m_nid.uID = uID;  // never changes after construction
   // Use resource string as tip if there is one
   AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
}
CTrayIcon::~CTrayIcon()
{
   SetIcon(0); // remove icon from system tray
}
//////////////////
// Set notification window. It must created already.
//
void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg)
{
   // If the following assert fails, you're probably
   // calling me before you created your window. Oops.
   ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd()));
   m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
   ASSERT(uCbMsg==0 || uCbMsg>=WM_USER);
   m_nid.uCallbackMessage = uCbMsg;
}
//////////////////
// This is the main variant for setting the icon.
// Sets both the icon and tooltip from resource ID
// To remove the icon, call SetIcon(0)
//
BOOL CTrayIcon::SetIcon(UINT uID)
{ 
   HICON hicon=NULL;
   if (uID) {
      AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
      hicon = AfxGetApp()->LoadIcon(uID);
   }
   return SetIcon(hicon, NULL);
}
//////////////////
// Common SetIcon for all overloads. 
//
BOOL CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip) 
{
   UINT msg;
   m_nid.uFlags = 0;
   // Set the icon
   if (hicon) {
      // Add or replace icon in system tray
      msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
      m_nid.hIcon = hicon;
      m_nid.uFlags |= NIF_ICON;
   } else { // remove icon from tray
      if (m_nid.hIcon==NULL)
         return TRUE;      // already deleted
      msg = NIM_DELETE;
   }
   // Use the tip, if any
   if (lpTip)
      strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
   if (m_nid.szTip[0])
      m_nid.uFlags |= NIF_TIP;
   // Use callback if any
   if (m_nid.uCallbackMessage && m_nid.hWnd)
      m_nid.uFlags |= NIF_MESSAGE;
   // Do it
   BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
   if (msg==NIM_DELETE || !bRet)
      m_nid.hIcon = NULL;  // failed
   return bRet;
}
/////////////////
// Default event handler handles right-menu and doubleclick.
// Call this function from your own notification handler.
//
LRESULT CTrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent)
{
   if (wID!=m_nid.uID ||
      (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
      return 0;
   // If there's a resource menu with the same ID as the icon, use it as 
   // the right-button popup menu. CTrayIcon will interprets the first
   // item in the menu as the default command for WM_LBUTTONDBLCLK
   // 
   CMenu menu;
   if (!menu.LoadMenu(m_nid.uID))
      return 0;
   CMenu* pSubMenu = menu.GetSubMenu(0);
   if (!pSubMenu) 
      return 0;
   if (lEvent==WM_RBUTTONUP) {
      // Make first menu item the default (bold font)
      ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
      // Display the menu at the current mouse location. There's a "bug"
      // (Microsoft calls it a feature) in Windows 95 that requires calling
      // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
      //
      CPoint mouse;
      GetCursorPos(&mouse);
      ::SetForegroundWindow(m_nid.hWnd);  
      ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0,
         m_nid.hWnd, NULL);
   } else  // double click: execute first menu item
      ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
   return 1; // handled
}Figure 6 CWindowPlacement
WINPLACE.H
 ////////////////////////////////////////////////////////////////
// CWindowPlacement 1996 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
////////////////
// CWindowPlacement reads and writes WINDOWPLACEMENT 
// from/to application profile and CArchive.
//
struct CWindowPlacement : public WINDOWPLACEMENT {
   CWindowPlacement();
   ~CWindowPlacement();
   
   // Read/write to app profile
   void GetProfileWP(LPCSTR lpKeyName);
   void WriteProfileWP(LPCSTR lpKeyName);
   // Save/restore window pos (from app profile)
   void Save(LPCSTR lpKeyName, CWnd* pWnd);
   BOOL Restore(LPCSTR lpKeyName, CWnd* pWnd);
   // Save/restore from archive
   friend CArchive& operator<<(CArchive& ar, const CWindowPlacement& wp);
   friend CArchive& operator>>(CArchive& ar, CWindowPlacement& wp);
};WINPLACE.CPP
 ////////////////////////////////////////////////////////////////
// CWindowPlacement 1996 Microsoft Systems Journal.
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
#include "stdafx.h"
#include "winplace.h"
CWindowPlacement::CWindowPlacement()
{
   // Note: "length" is inherited from WINDOWPLACEMENT
   length = sizeof(WINDOWPLACEMENT);
}
CWindowPlacement::~CWindowPlacement()
{
}
//////////////////
// Restore window placement from profile key
BOOL CWindowPlacement::Restore(LPCSTR lpKeyName, CWnd* pWnd)
{
   GetProfileWP(lpKeyName);
   // Only restore if window intersets the screen.
   //
   CRect rcTemp, rcScreen(0,0,GetSystemMetrics(SM_CXSCREEN),
      GetSystemMetrics(SM_CYSCREEN));
   if (!::IntersectRect(&rcTemp, &rcNormalPosition, &rcScreen))
      return FALSE;
   pWnd->SetWindowPlacement(this);  // set placement
   return TRUE;
}
//////////////////
// Get window placement from profile.
void CWindowPlacement::GetProfileWP(LPCSTR lpKeyName)
{
   CWinApp *pApp = AfxGetApp();
   ASSERT_VALID(pApp);
   showCmd = pApp->GetProfileInt(lpKeyName, "wp.showCmd", showCmd);
   flags   = pApp->GetProfileInt(lpKeyName, "wp.flags", flags);
ptMinPosition.x = pApp->GetProfileInt(lpKeyName, "wp.ptMinPosition.x", 
      ptMinPosition.x);
ptMinPosition.y = pApp->GetProfileInt(lpKeyName, "wp.ptMinPosition.y",
      ptMinPosition.y);
ptMaxPosition.x = pApp->GetProfileInt(lpKeyName, "wp.ptMaxPosition.x", 
      ptMaxPosition.x);
ptMaxPosition.y = pApp->GetProfileInt(lpKeyName, "wp.ptMaxPosition.y",
      ptMaxPosition.y);
   RECT& rc = rcNormalPosition;  // because I hate typing
   rc.left  = pApp->GetProfileInt(lpKeyName, "wp.left",   rc.left);
   rc.right = pApp->GetProfileInt(lpKeyName, "wp.right",  rc.right);
   rc.top   = pApp->GetProfileInt(lpKeyName, "wp.top",    rc.top);
   rc.bottom= pApp->GetProfileInt(lpKeyName, "wp.bottom", rc.bottom);
}
////////////////
// Save window placement in app profile
void CWindowPlacement::Save(LPCSTR lpKeyName, CWnd* pWnd)
{
   pWnd->GetWindowPlacement(this);
   WriteProfileWP(lpKeyName);
}
//////////////////
// Write window placement to app profile
void CWindowPlacement::WriteProfileWP(LPCSTR lpKeyName)
{
   CWinApp *pApp = AfxGetApp();
   ASSERT_VALID(pApp);
   pApp->WriteProfileInt(lpKeyName, "wp.showCmd",         showCmd);
   pApp->WriteProfileInt(lpKeyName, "wp.flags",           flags);
   pApp->WriteProfileInt(lpKeyName, "wp.ptMinPosition.x", ptMinPosition.x);
   pApp->WriteProfileInt(lpKeyName, "wp.ptMinPosition.y", ptMinPosition.y);
   pApp->WriteProfileInt(lpKeyName, "wp.ptMaxPosition.x", ptMaxPosition.x);
   pApp->WriteProfileInt(lpKeyName, "wp.ptMaxPosition.y", ptMaxPosition.y);
   pApp->WriteProfileInt(lpKeyName, "wp.left",  rcNormalPosition.left);
   pApp->WriteProfileInt(lpKeyName, "wp.right", rcNormalPosition.right);
   pApp->WriteProfileInt(lpKeyName, "wp.top",   rcNormalPosition.top);
   pApp->WriteProfileInt(lpKeyName, "wp.bottom",rcNormalPosition.bottom);
}
// The ugly casts are required to help the VC++ 3.0 compiler decide which
// operator<< or operator>> to use. If you're using VC++ 4.0 or later, you 
// can delete this stuff.
//
#if (_MSC_VER < 1000)      // 1000 = VC++ 4.0
#define UINT_CAST (LONG)
#define UINT_CASTREF (LONG&)
#else
#define UINT_CAST
#define UINT_CASTREF
#endif
//////////////////
// Write window placement to archive
// WARNING: archiving functions are untested.
CArchive& operator<<(CArchive& ar, const CWindowPlacement& wp)
{
   ar << UINT_CAST wp.length;
   ar << UINT_CAST wp.flags;
   ar << UINT_CAST wp.showCmd;
   ar << wp.ptMinPosition;
   ar << wp.ptMaxPosition;
   ar << wp.rcNormalPosition;
   return ar;
}
//////////////////
// Read window placement from archive
// WARNING: archiving functions are untested.
CArchive& operator>>(CArchive& ar, CWindowPlacement& wp)
{
   ar >> UINT_CASTREF wp.length;
   ar >> UINT_CASTREF wp.flags;
   ar >> UINT_CASTREF wp.showCmd;
   ar >> wp.ptMinPosition;
   ar >> wp.ptMaxPosition;
   ar >> wp.rcNormalPosition;
   return ar;
}Figure 7 TWMOD.CPP
 ///////////////////////////////////////////////////////////////////////////
// Changes to TRACEWIN that implement saving/restoring the window position.
// (From MainFrm.h)
class CMainFrame : public CFrameWnd {
public:
   static const char* REGKEY; // registry key for saved settings
                                     .
                                     .
                                     .
};
// (From MainFrm.cpp, TRACEWIN's main window)
const char* CMainFrame::REGKEY = "Settings";
void CMainFrame::OnClose() 
{
   // Save current settings in registry
   CWindowPlacement wp;
   wp.Save(REGKEY, this);
                                     .
                                     . (Save other stuff too)
                                     .
CFrameWnd::OnClose();
}
// (From App.cpp, TRACEWIN's app object)
BOOL CApp::InitInstance()
{
   // Save settings in registry, not INI file
   SetRegistryKey("MSJ");
                                     .
                                     . Create main window
                                     .
// Load window placement from profile
   CWindowPlacement wp;
   if (!wp.Restore(CMainFrame::REGKEY, pMainFrame))
      pMainFrame->ShowWindow(m_nCmdShow);
                                     .
                                     .
                                     .
   return TRUE;
}