Question

I'm trying to write a simple reusable class to encapsulte the functionality for a basic tray icon. This is my first "project" with C++, and I'm having some problems: the message-only window created for the tray icon does not receive any message. The icon is visible in the tray and has the correct tooltip, but clicking on it does not send any message to my invisible window.

To test if the function WindowProcedure was called, i added a printf statement, and the output is that the function is called 4 times upon creation, but no more, even if I click on the notify icon.

Why my window does not receive any message from the tray icon?

This is what I've managed to write:

TrayIcon.h:

class TrayIcon {

    public:
        TrayIcon();
        ~TrayIcon();
        void Show();
        /*...*/
        static void Initialize();


    private:
        static LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
        /*...*/    
};

TrayIcon.cpp:

// Static initializer
int TrayIcon::_idCounter = 1;
void TrayIcon::Initialize() // This method is called just once
{
    // Registers the class for the tray windows
    WNDCLASSEX wx = {};
    wx.lpfnWndProc = TrayIcon::WindowProcedure;
    wx.lpszClassName = TRAYICON_WINDOW_CLASSNAME;
    wx.cbSize = sizeof(WNDCLASSEX);
    RegisterClassEx(&wx);
}

// Constructor
TrayIcon::TrayIcon()
{
    // Creates an hidden message-only window
    HWND hWnd = CreateWindowEx(0, TRAYICON_WINDOW_CLASSNAME, "trayiconwindow", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)this);

    // Creates the notify icon
    NOTIFYICONDATA icon;
    memset( &icon, 0, sizeof( NOTIFYICONDATA ) ) ;
    icon.cbSize = sizeof(NOTIFYICONDATA);
    icon.hWnd = hWnd;
    icon.uID = TrayIcon::_idCounter++;
    icon.uCallbackMessage = WM_TRAYICON; //Set up our invented Windows Message
    icon.uFlags = NIF_MESSAGE;
    this->_iconData = icon;
}

// Shows the tray icon
void TrayIcon::Show()
{
    // ...
    Shell_NotifyIcon(NIM_ADD, &this->_iconData);
}

// Processes the messages received by the hidden window for each icon
LRESULT CALLBACK TrayIcon::WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    TrayIcon* icon = (TrayIcon*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    printf("Window Procedure called.\n\r");
    return DefWindowProc(hwnd, message, wParam, lParam);
}

And this is how I use the class:

int main()
{
    // Creates a new Tray icon
    TrayIcon::Initialize();
    TrayIcon* icon = new TrayIcon();
    icon->SetTooltip("Foo Tooltip");
    icon->SetIcon(...);
    icon->Show();

    // Waits for user input
    void* tmp;
    cin >> tmp;
    return 0;
}

Thank you for your time.

Was it helpful?

Solution

You need some form of message loop, not a blocking call to input something. Try the canonical message loop:

MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top