|
// Shell Icon Helper - by Jon Taylor, for Code Project
// See documentation on Code Project web site for information on how
// to use this class.
#ifndef __SHELLICONHELPER_H
#define __SHELLICONHELPER_H
#include <string>
#include <atlwin.h>
template <typename T>
class CShellIconHelper : public CWindowImpl<T>
{
private:
virtual HRESULT CreateShell ()
{
RECT rect;
rect.left = rect.right = rect.top = rect.bottom = 0;
// Create a hidden window (using CWindowImpl)
HWND hWnd = Create (NULL, rect, "ShellIconHiddenWindow", WS_POPUP);
if (hWnd != 0) // Was created?
{
// Add the icon into the shell
ShellNotify (NIM_ADD);
return S_OK;
}
else return HRESULT_FROM_WIN32 (GetLastError());
}
virtual void DestroyShell ()
{
ShellNotify (NIM_DELETE); // Remove the icon
if (m_hWnd != NULL)
{
// Get rid of the hidden window
DestroyWindow();
}
}
void ShellNotify (DWORD msg)
{
m_CurrentText = m_CurrentText;
m_CurrentIconResource = m_CurrentIconResource;
NOTIFYICONDATA notifyIconData;
notifyIconData.cbSize = sizeof(notifyIconData);
notifyIconData.hWnd = m_hWnd;
notifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
notifyIconData.uCallbackMessage = WM_USER;
notifyIconData.uID = 0;
notifyIconData.hIcon = ::LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE (m_CurrentIconResource));
::lstrcpyn(notifyIconData.szTip, m_CurrentText.c_str(), 64); // Limit to 64 chars
::Shell_NotifyIcon (msg, ¬ifyIconData);
}
public:
CShellIconHelper ()
{
// Initialise internal variables to known good state
m_bVisible = false;
m_bTimerActive = false;
m_TimerId = 0;
m_wTimerDuration = 0;
m_CurrentIconResource = 0;
m_CurrentText = std::string("");
}
virtual void SetShellTipText (std::string &TipText)
{
// Save this text for when we update
m_CurrentText = TipText;
ShellNotify (NIM_MODIFY);
}
virtual void SetShellIcon (WORD IconResource)
{
// Save this icon resource for when we update
m_CurrentIconResource = IconResource;
ShellNotify (NIM_MODIFY);
}
virtual void SetShellTimer (bool bEnabled, WORD wTimerDuration = 1000)
{
if (bEnabled == true) // User wants to start a timer
{
if (m_bTimerActive = true)
{
::KillTimer (m_hWnd, m_TimerId);
}
// Start the timer
m_TimerId = ::SetTimer (m_hWnd, 1, wTimerDuration, NULL);
}
else // User wants to shut down the timer
{
if (m_bTimerActive = true)
{
::KillTimer (m_hWnd, m_TimerId);
}
}
m_wTimerDuration = wTimerDuration;
m_bTimerActive = bEnabled;
}
virtual void SetShellVisible (bool bVisible = true)
{
if (bVisible == true) // User wants to show the icon in the shell
{
if (m_bVisible == false) // Doesn't already exist?
{
// Create the shell, and timer (if applicable)
CreateShell ();
} // Otherwise, well you already have icon in the shell. :-)
SetShellTimer (m_bTimerActive, m_wTimerDuration);
}
else // User wants rid of the icon
{
if (m_bVisible == true) // Is it there already?
{
// Destroy any running timer
if (m_bTimerActive == true)
{
::KillTimer (m_hWnd, m_TimerId);
}
DestroyShell (); // Get rid
}
}
m_bVisible = bVisible;
}
virtual WORD ShowPopupMenu (WORD PopupMenuResource)
{
HMENU hMenu, hPopup = 0;
hMenu = ::LoadMenu (_Module.GetModuleInstance(), MAKEINTRESOURCE (PopupMenuResource));
if (hMenu != 0)
{
POINT pt;
::GetCursorPos (&pt);
// TrackPopupMenu cannot display the menu bar so get
// a handle to the first shortcut menu.
hPopup = ::GetSubMenu (hMenu, 0);
// To display a context menu for a notification icon, the
// current window must be the foreground window before the
// application calls TrackPopupMenu or TrackPopupMenuEx. Otherwise,
// the menu will not disappear when the user clicks outside of the menu
// or the window that created the menu (if it is visible).
::SetForegroundWindow (m_hWnd);
WORD cmd = ::TrackPopupMenu (hPopup, TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, m_hWnd, NULL);
// See MS KB article Q135788
::PostMessage (m_hWnd, WM_NULL, 0, 0);
// Clear up the menu, we're not longer using it.
::DestroyMenu (hMenu);
return cmd;
}
return 0;
}
private:
bool m_bVisible;
bool m_bTimerActive;
UINT_PTR m_TimerId;
WORD m_wTimerDuration;
int m_CurrentIconResource;
std::string m_CurrentText;
};
#endif
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I first started tinkering with a ZX81 back in 1981 and it's lovely blocky graphics, teaching myself Z80 assembler and BASIC. I come from a hardware background and electronics - I started out in embedded software for avionics but soon moved onto PC platforms.
Java and C++ are my prefered language but also dabble in VB and .NET.
I'm a team leader with Nokia developing Series 40 features - it's a cool place to work!