c++windowssystem-traynotification-area

C++ event handling for click on notification area Icon Windows


I want to achieve some kind of event handling for Windows. I have a program, that has a symbol in the Notification Area (System Tray) and I want the programm to show up again, when the user clicks on the Icon. Is there a simple Way to implement that in c++ as an Event? I have only found ways to this in C#.

It is a console Application and I want to change as few things as possible. But there is no WndProc handler for Console Application as far as I can tell.


Solution

  • Why no WndProc? Console application is a perfect win32 application, and it can use anything which non-console application can use.

    Here's a simple, but a bit long example.

    #include <windows.h>
    #include <shellapi.h>
    
    #include <iostream>
    #include <cstring>
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
    BOOL WINAPI ConsoleRoutine(DWORD dwCtrlType);
    
    LPCWSTR lpszClass = L"__hidden__";
    
    int main()
    {
        HINSTANCE hInstance = GetModuleHandle(nullptr);
    
        WNDCLASS wc;
        HWND hWnd;
        MSG msg;
    
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hbrBackground = nullptr;
        wc.hCursor = nullptr;
        wc.hIcon = nullptr;
        wc.hInstance = hInstance;
        wc.lpfnWndProc = WndProc;
        wc.lpszClassName = lpszClass;
        wc.lpszMenuName = nullptr;
        wc.style = 0;
        RegisterClass(&wc);
    
        hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
            nullptr, nullptr, hInstance, nullptr);
    
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return static_cast<int>(msg.wParam);
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {
        static NOTIFYICONDATA nid;
    
        switch (iMsg)
        {
            case WM_CREATE:
                std::memset(&nid, 0, sizeof(nid));
                nid.cbSize = sizeof(nid);
                nid.hWnd = hWnd;
                nid.uID = 0;
                nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
                nid.uCallbackMessage = WM_APP + 1;
                nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
                lstrcpy(nid.szTip, L"con-notify");
                Shell_NotifyIcon(NIM_ADD, &nid);
                Shell_NotifyIcon(NIM_SETVERSION, &nid);
                return 0;
            case WM_APP + 1:
                switch (lParam)
                {
                    case WM_LBUTTONDBLCLK:
                        std::cout << "notify dblclk" << std::endl;
                        break;
                    case WM_RBUTTONDOWN:
                    case WM_CONTEXTMENU:
                        break;
                }
                break;
            case WM_DESTROY:
                Shell_NotifyIcon(NIM_DELETE, &nid);
                MessageBox(nullptr, L"asdf", L"asdf", MB_OK);
                PostQuitMessage(0);
                return 0;
        }
        return DefWindowProc(hWnd,iMsg,wParam,lParam);
    }
    

    You probably want not to mess up your console program with message loop. If so, you can put notification code into another thread.