Click here to Skip to main content
Click here to Skip to main content

A Simple DLL useful to manage taskbar icons

, 22 Apr 2004
Rate this:
Please Sign up or sign in to vote.
This article describes a software (DLL) useful to manage icon visualization on the Windows taskbar with a popup menu.

Introduction

The code provided with this article should be useful to manage the visualization of an icon on the Windows task bar. The code encapsulates the stuff required for handling mouse events, offering to the user a clean and simple interface.

We will use C++ without MFC and STL. We directly use SDK APIs.

Background

In order to show an icon on the Windows taskbar, we can use the Windows API Shell_NotifyIcon. This API allows the programmer to add, delete and modify a certain icon in a straightforward way. A little bit difficult stuff occurs when one likes to manage mouse events on the icon and show a popup menu.

The code we propose in this article allows the user to show and modify an icon on the Windows taskbar, manage mouse events and control a popup menu using a simple interface, without taking care of threading and windowing. The code is encapsulated in a DLL so it should be simple to use in all "C++ like contexts" such as ATL, Console, MFC and Windows application projects.

We've tested the code (developed using Visual Studio 6.0) in Windows ME, 2000 and XP operating systems.

Managing mouse events

For managing mouse events, we'll use a background window. The thread associated with this window (TaskBarThread) will receive the messages sent by the operating system when the user works on the icon (e.g. left click, right click, ...). Then, the message loop of this thread brings the events to the specified user defined window procedure (TaskBarWinProc). The following picture shows the flow of a message generated by the user when clicking on the icon.

Sample Image

Figure 1

Managing popup

For managing popup, we'll use a background window as well (associated to the thread PopupThread and window procedure PopupWinProc). This window will show the popup on receiving a right click event sent by the thread managing mouse events. The following picture shows the flow of a message generated by the user when right-clicking on the icon and selecting a popup item.

Sample Image

Figure 2

Using the code

Following the "download source" link above, you can get the source code of the DLL (folder taskbaricon_dll) and the source code of a simple console application using the DLL (folder taskbaricon_console). Following the "download demo project", you can get precompiled files ready to use (folder taskbaricon_demo).

The console application shows an icon on the taskbar and reacts to mouse and popup selection events showing a message box describing the event. Further, it allows the user to change icon appearance (i.e. icon frame) pressing a key.

The dynamic link library (DLL) exports two interfaces. The former interface, ISimpleUnknown, is provided to manage a reference counter. This interface is similar to COM interface IUnknown, except for the lack of the method QueryInterface. It is useful for delegating memory allocation & de-allocation to the library instead of the application. Note that, since we use some threads, it is the library that knows exactly when the memory is no longer needed. This interface is just a way to manage memory allocation/de-allocation.

class ISimpleUnknown
{   
public:
    // The following method increments the reference counter.
    virtual ULONG AddRef()=0;

    // The following method decreases the reference counter.
    // If the reference count is equal to 0, it deletes 
    // the instance of ITaskBarIcon.
    virtual ULONG Release()=0;

    // The following method returns the reference counter current value.
    virtual ULONG GetRef()=0;
};

The latter interface, ITaskBarIcon, is the "core" interface. It keeps the code for showing an icon on the taskbar, showing a popup and for managing events.

Note: for getting a pointer to this interface, we have to call the static method Create (instead of the usual new). This method automatically sets the reference pointer to 1. For releasing the pointer, we have to use the method Release (instead of the usual delete).

The function pointer type LP_HANDLER_FUNC is used for setting up a callback (listener) for managing mouse events. This function will be called by the DLL when a mouse event occurred on the icon. The parameters the DLL will pass to the application are: icon name (char*), mouse event X coordinate (int) and mouse event Y coordinate (int).

The function pointer type LP_POPUP_HANDLER_FUNC is used to set up a callback (listener) for managing popup events. The DLL will pass back to the application an identifier (int) that indicates the popup item selected by the user.

Note: we think about a "taskbar icon" as composed by several "icon frames". Only one "icon frame" is showed for each moment. An "icon frame" is implemented as a common Windows icon object (i.e. HICON). This allows us to create a dynamic icon. Each "icon frame" is represented with a string set by the application using the parameter p_IconName of the method SetIconFrame. This string will be passed back by the DLL to the application when a mouse event occurs.

// --------------------------------------------------------------------------
// The function pointer type LP_HANDLER_FUNC is used 
// to set up a callback (listener) for managing mouse events.
// --------------------------------------------------------------------------
typedef void (__stdcall *LP_HANDLER_FUNC)(char*, int, int);

// --------------------------------------------------------------------------
// The function pointer type LP_POPUP_HANDLER_FUNC is used 
// to set up a callback (listener) for managing popup events.
// --------------------------------------------------------------------------
typedef void (__stdcall *LP_POPUP_HANDLER_FUNC)(int);

class ITaskBarIcon : virtual public ISimpleUnknown
{
public:
    // The following method allows application to set an icon resource (i.e. HICON). 
    // Each of these icons corresponds to one icon frame.
    virtual void SetIconFrame(
            char*    p_IconName, 
            HICON    p_IconHandle, 
            UINT     p_IconUID, 
            char*    p_IconTooltipText)=0;

    // The following method allows application to change icon appearence. 
    // It replaces the current showed icon frame
    // with one individuated by the parameter.
    virtual void ChangeIconFrame(char* p_IconName)=0;

    // The following method creates two hidden windows (one for icon and 
    // one for popup) and starts 
    // threads needed for managing events.
    // Further it shows the initial icon on the taskbar.
    virtual void Start(char* p_IconName)=0;

    // The following method deletes the currently showed icon and 
    // stops threads for managing events.
    virtual void Stop()=0;

    // The following methods are used for registering event handlers.
    // They allows application to manage mouse events 
    // (e.g. click, double click, ...) on the currently showed icon).
    virtual void SetLeftButtonClickHandler(LP_HANDLER_FUNC p_Handler)=0; 
    virtual void SetRightButtonClickHandler(LP_HANDLER_FUNC p_Handler)=0;
    virtual void SetLeftButtonDoubleClickHandler(LP_HANDLER_FUNC p_Handler)=0;

    // The following method allows application to set up a popup menu.
    // Application should call this method for each menu item it wants 
    // to appear in the popup. The menu item identifier will be returned
    // in the callback when the user selects this item. 
    // Using this application will be able to discover which
    // item the user selected on the popup.
    virtual void SetPopupMenuItem(
            char*    p_MenuItemString, 
            int      p_MenuItemIdentifier)=0;

    // The following method can be used to set up a callback function
    // that will be called when the user selects an item of the popup menu.
    virtual void SetPopupHandler(LP_POPUP_HANDLER_FUNC p_Handler)=0;

    // The following method creates an instance of ITaskBarIcon.
    // The reference counter is automatically set to 1.
    static ITaskBarIcon* Create();
};

Note: For compatibility reasons, in our interfaces, we don't use STL nor MFC. Instead, we'll use simple strings (char*) and simple "C style" arrays. The following "defines" fix the max dimensions allowed for strings and arrays.

#define    MAX_ICON_NUM                  100 // Max number of icon frames.
#define    MAX_ICON_NAME_STRLEN          50  // Max dimension of icon name string.
#define    MAX_ICON_TOOLTIP_TEST_STRLEN  255 // Max dimension of icon tooltip string.
#define    MAX_POPUP_ITEM                50  // Max number of popup menu items.
#define    MAX_POPUP_ITEM_STRLEN         50  // Max dimension of popup item text.

Let's see how to use the interfaces exported by the DLL. The following notes describe the console application supplied with this article.

First of all, it is necessary to include the taskbaricon.h header file.

After that, we can define the callbacks for mouse events and popup selection. When an event occurs on the icon (e.g. mouse left click, mouse right click, ...), or on the popup menu (e.g. the user shows the popup by right clicking and selects an item), the DLL will take care of calling the proper callback. Later, we will show how to register these callbacks.

Let's see the callbacks for mouse events. Note that the first parameter of each callback represents a certain icon frame. The parameters p_x and p_y are the mouse coordinates in which the event has taken place. For instance, they could be useful for showing a dialog box.

// Callbacks for managing mouse events on showed icon.
void __stdcall LeftButtonClickHandler(
    char* p_IconNameCurrentlyShowed, 
    int p_x, 
    int p_y
)
{
    char l_Str[MAX_PATH];
    sprintf(
        l_Str,
        "(CurrentIconFrameName: %s) LeftButtonClickHandler 
                      mouse coordinates <x,y>==<%u,%u>",
        p_IconNameCurrentlyShowed
        p_x,
        p_y);

    ::MessageBox(
        NULL,
        l_Str,
        "Application Event Handler",
        MB_OK);
}

void __stdcall RightButtonClickHandler(
    char* p_IconNameCurrentlyShowed,
    int p_x, 
    int p_y
)
{
    char l_Str[MAX_PATH];
    sprintf(
        l_Str,
        "(CurrentIconFrameName: %s) RightButtonClickHandler 
                       mouse coordinates <x,y>==<%u,%u>",
        p_IconNameCurrentlyShowed
        p_x,
        p_y);

    ::MessageBox(
        NULL,
        l_Str,
        "Application Event Handler",
        MB_OK);
}

void __stdcall LeftButtonDoubleClickHandler(
    char* p_IconNameCurrentlyShowed,
    int p_x, 
    int p_y
)
{
    char l_Str[MAX_PATH];
    sprintf(
        l_Str,
        "(CurrentIconFrameName: %s) LeftButtonDoubleClickHandler 
                              mouse coordinates <x,y>==<%u,%u>",
        p_IconNameCurrentlyShowed
        p_x,
        p_y);


    ::MessageBox(
        NULL,
        l_Str,
        "Application Event Handler",
        MB_OK);

}

After that, we can define a callback for popup menu. The parameter p_MenuItemIdentifier identifies the user choice. The possible values for this parameter are defined by the programmer and passed to the DLL using the API SetPopupMenuItem described later.

// Callbacks for managing user selection on popup menu.
void __stdcall PopupUserActionHandler(int p_MenuItemIdentifier)
{
    char l_Text1[]="Option1";
    char l_Text2[]="Option2";
    char l_Text3[]="Option3";

    char l_Str[MAX_PATH];

    char l_UserChoice[MAX_PATH];
    if (p_MenuItemIdentifier==1)
    {
        strcpy(l_UserChoice,l_Text1);
    }
    else
    if (p_MenuItemIdentifier==2)
    {
        strcpy(l_UserChoice,l_Text2);
    }
    else
    if (p_MenuItemIdentifier==3)
    {
        strcpy(l_UserChoice,l_Text3);
    }
    else
    {
        strcpy(l_UserChoice,"Unknown");
    }

    sprintf(l_Str,"User selection: %s", l_UserChoice);
    MessageBox(NULL,l_Str,"Popup menu user choice",MB_OK);

}

Then it is necessary to create a "task bar icon" object. We'll use the methods Create and Release instead of new and delete to improve code separation.

Note that the reference counter is automatically set to 1.

ITaskBarIcon* l_TaskBarIcon = ITaskBarIcon::Create();

Then we need to create a set of icons. Each of these icons represent one possible "icon frame". In this example, we define a taskbar icon with 4 frames. Each of this frame represents a possible status for the application. These frames are identified with the strings "Disactivated", "Activated", "Idle", "Working".

HINSTANCE hInstance = (HINSTANCE) GetModuleHandle (NULL); 
HICON l_Icon1 = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON1));
HICON l_Icon2 = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON2));
HICON l_Icon3 = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON3));
HICON l_Icon4 = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_ICON4));

Then we need to add the previously created icons to our task bar icon object. Each of this icon will be one frame of the task bar icon object. For each moment, a single named frame will be showed.

l_TaskBarIcon->SetIconFrame(
        "Disactivated", 
        l_Icon1, 
        IDI_ICON1, 
        "Process Disactivated");

l_TaskBarIcon->SetIconFrame(
        "Activated", 
        l_Icon2, 
        IDI_ICON2, 
        "Process Activated");

l_TaskBarIcon->SetIconFrame(
        "Idle", 
        l_Icon3, 
        IDI_ICON3, 
        "Process Idle");

l_TaskBarIcon->SetIconFrame(
        "Working", 
        l_Icon4, 
        IDI_ICON4, 
        "Process Working");

After that, we can set up a popup menu. This will be shown when the user right clicks on the icon. For doing that, we need to set the items belonging to the popup using the method SetPopupMenuItem. The first parameter is the string that will be shown in the item. The second parameter is the identifier of the item that will be returned in the popup callback whether the user selects this item.

l_TaskBarIcon->SetPopupMenuItem(
        "Option1", 
        1);

l_TaskBarIcon->SetPopupMenuItem(
        "Option2", 
        2);

l_TaskBarIcon->SetPopupMenuItem(
        "Option3", 
        3);

Then we can register the various event handlers defined above.

// Handler for getting mouse events on the showed taskbar icon.
l_TaskBarIcon->SetLeftButtonClickHandler(LeftButtonClickHandler);
l_TaskBarIcon->SetRightButtonClickHandler(RightButtonClickHandler);
l_TaskBarIcon->SetLeftButtonDoubleClickHandler(LeftButtonDoubleClickHandler);

// Handler for getting user selection on icon popup menu.
l_TaskBarIcon->SetPopupHandler(PopupUserActionHandler);

Then we need to call the following method. This is necessary to start windowing management and to show the initial frame (i.e. icon named "Disactivated") of our icon on the taskbar.

l_TaskBarIcon->Start("Disactivated");

In order to change the current icon frame shown, we can use the method ChangeIcon.

// Change the hicon appearence according to certain events.

//...

l_TaskBarIcon->ChangeIconFrame("Idle");

//...

l_TaskBarIcon->ChangeIconFrame("Activated");

//...

l_TaskBarIcon->ChangeIconFrame("Working");

//...

l_TaskBarIcon->ChangeIconFrame("Idle");

//...

l_TaskBarIcon->ChangeIconFrame("Disactivated");

In order to quit the task bar icon and the popup threads, we need to call the following method:

l_TaskBarIcon->Stop();

At last, we need to deallocate our task bar icon object. Note that we have to call the method Release instead of using the delete instruction directly. The DLL will call delete internally, when all threads will be ended.

l_TaskBarIcon->Release();

Limitations

  • It is possible to set a callback for only three mouse events (e.g. left click, right click and double left click).
  • It is necessary to improve error management. A lot of error situations, although they are envisioned, are not managed.
  • It is not possible to change the icon tooltip in a dynamic way.
  • ...

History

  • 16.04.2004
    • First version
  • 20.04.2004
    • Minor syntax error corrections in the article;
    • "Figure 1" and "Figure 2" updated;
    • Minor code tuning.

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

Share

About the Author

Manuele Sicuteri
Web Developer
Italy Italy
I'm graduated in computer science and I'm working as a software analyst and programmer in the field of medical information technology.

Comments and Discussions

 
GeneralMultithreaded scanner PinmemberJRaiden16-Feb-06 23:03 
Is this dll threadsafe multithreaded ?
Just wondering if this concept could be used for the following scenario.
 
I want to have a dynamically loaded Win32 DLL that can be setup to scan certain registry or folder locations.
 
As it recurses it sends notifications back to the client app, be it MFC via callbacks. How do I prevent deadlocks in a multithreaded scenario i.e PostMessage.
 
I want the dll to be multithreaded so many instances of scans can be setup.
 
How can I effectively make a Win32 DLL to callback to a gui, update a static control of its location in the scan.
 
Is this taskbar dll example a good starting point to build a multithreaded dll that notifies a gui and everything is responsive.
Does anyone have any source examples of a simple implementation of Win32 Multithreading dlls updating a gui.
 
If anyone can help please email me at lgraiden@xsmail.com with any suggestions or respond to this message.
 
All the best
John

GeneralExcellent stuff - though a slight misnomer Pinmembergrigri21-Aug-04 1:24 
GeneralGood Work PinmemberHumanOsc15-Apr-04 23:45 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411019.1 | Last Updated 23 Apr 2004
Article Copyright 2004 by Manuele Sicuteri
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid