系统托盘图标

系统托盘图标

系统托盘图标的创建主要使用 Shell_NotifyIcon 函数来实现,实现过程比较简单。

注意:
要创建系统托盘图标,必须要有窗口;要创建窗口,必须要有窗口过程函数。
一个窗口可以有多个系统托盘图标;图标彼此间用 hWnd 和 uID 区分;
窗口过程函数接收到事件后, wParam 表示 uID,lParam 表示 message;


以下是封装的托盘类代码:

// notifyicon.h

#ifndef _NOTIFYICON_H_
#define _NOTIFYICON_H_
#include <windows.h>
#include <shellapi.h>
#include <map>

typedef VOID (*NotifyIconCallback) (UINT uID, UINT message);

class NotifyIcon
{
public:
    static UINT AddIcon(HICON hIcon, WCHAR* szTip);
    static VOID DelIcon(UINT uID);
    static VOID ModIcon(UINT uID, HICON hIcon, WCHAR* szTip);
    static UINT Attach(NotifyIconCallback pCallback);
    static VOID Detach(UINT uCookie);

private:
    static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

private:
    static HWND m_hWnd;
    static UINT m_uCookieCount;
    static std::map<UINT,NotifyIconCallback> m_mapCallback;
    static UINT m_uIDCount;
    static std::map<UINT,NOTIFYICONDATA> m_mapNotifyData;
};

#endif

// notifyicon.cpp

#include "notifyicon.h"

HWND NotifyIcon::m_hWnd = NULL;
UINT NotifyIcon::m_uCookieCount = 0;
std::map<UINT,NotifyIconCallback> NotifyIcon::m_mapCallback;
UINT NotifyIcon::m_uIDCount = 0;
std::map<UINT,NOTIFYICONDATA> NotifyIcon::m_mapNotifyData;

UINT NotifyIcon::AddIcon( HICON hIcon, WCHAR* szTip )
{
    // 创建窗口
    LPCTSTR pszClassName = TEXT("NotifyIcon_ClassName");
    LPCTSTR pszWndName = TEXT("NotifyIcon_WndName");
    HINSTANCE hInstance = GetModuleHandle(NULL);
    WNDCLASS wndClass;
    if (GetClassInfo(hInstance, pszClassName, &wndClass) == 0)
    {
        wndClass.style = CS_HREDRAW | CS_VREDRAW;
        wndClass.lpfnWndProc = NotifyIcon::WndProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = hInstance;
        wndClass.hIcon = NULL;
        wndClass.hCursor = NULL;
        wndClass.hbrBackground = NULL;
        wndClass.lpszClassName = pszClassName;
        wndClass.lpszMenuName = NULL;
        if (RegisterClass(&wndClass) == NULL)
        {
            return NULL;
        }
    }
    if (FindWindow(pszClassName, pszWndName) == NULL)
    {
        m_hWnd = CreateWindowEx(WS_EX_TOOLWINDOW,
            pszClassName, pszWndName, 
            WS_POPUP,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL, NULL, hInstance, NULL);
        if (m_hWnd == NULL)
        {
            return NULL;
        }
    }

    UINT uID = m_uIDCount;
    m_uIDCount++;
    
    NOTIFYICONDATA nd;
    nd.cbSize = sizeof(nd);
    nd.hWnd = m_hWnd;
    nd.uID = uID;
    nd.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nd.uCallbackMessage = WM_USER;
    nd.hIcon = hIcon;
    if (szTip != NULL && lstrlen(szTip) < 127)
    {
        lstrcpy(nd.szTip, szTip);
    }
    if(Shell_NotifyIcon(NIM_ADD, &nd) == TRUE)
    {
        m_mapNotifyData.insert(std::make_pair(uID, nd));
        return uID;
    }

    return NULL;
}

VOID NotifyIcon::DelIcon( UINT uID )
{
    if (m_hWnd == NULL)
    {
        return;
    }
    std::map<UINT, NOTIFYICONDATA>::iterator iter = m_mapNotifyData.find(uID);
    if (iter != m_mapNotifyData.end())
    {
        Shell_NotifyIcon(NIM_DELETE, &(iter->second));
        m_mapNotifyData.erase(iter);
    }
}

VOID NotifyIcon::ModIcon( UINT uID, HICON hIcon, WCHAR* szTip )
{
    if (m_hWnd == NULL)
    {
        return;
    }
    std::map<UINT, NOTIFYICONDATA>::iterator iter = m_mapNotifyData.find(uID);
    if (iter != m_mapNotifyData.end())
    {
        if (hIcon != NULL)
        {
            iter->second.hIcon = hIcon;
        }
        if (szTip && lstrlen(szTip) < 127)
        {
            lstrcpy(iter->second.szTip, szTip);
        }
        else
        {
            lstrcpy(iter->second.szTip, L"");
        }
        Shell_NotifyIcon(NIM_MODIFY, &(iter->second));
    }
}

UINT NotifyIcon::Attach( NotifyIconCallback pCallback )
{
    if (pCallback == NULL)
    {
        return NULL;
    }
    UINT uCookie = m_uCookieCount;
    m_uCookieCount ++;

    m_mapCallback.insert(std::make_pair(uCookie, pCallback));
    return uCookie;
}

VOID NotifyIcon::Detach( UINT uCookie )
{
    std::map<UINT, NotifyIconCallback>::iterator iter = m_mapCallback.find(uCookie);
    if (iter != m_mapCallback.end())
    {
        m_mapCallback.erase(iter);
    }
}

LRESULT CALLBACK NotifyIcon::WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    switch(message)
    {
    case WM_CREATE:
        break;
    case WM_DESTROY:
        break;
    case WM_USER:
        for (std::map<UINT, NotifyIconCallback>::iterator iter = m_mapCallback.begin(); iter != m_mapCallback.end(); ++iter)
        {
            NotifyIconCallback pCallback = iter->second;
            pCallback(wParam, lParam);        // wParam --> uID, lParam --> message
        }
        break;
    default:
        break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

// main.cpp 测试

#include <windows.h>
#include "notifyicon.h"

void callbackFunc(UINT uID, UINT message);

int main()
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    HICON hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    WCHAR szTip[128] = L"哈哈哈";
    UINT uID1 = NotifyIcon::AddIcon(hIcon, szTip);
    UINT uID2 = NotifyIcon::AddIcon(hIcon, szTip);
    UINT uID3 = NotifyIcon::AddIcon(hIcon, szTip);
    NotifyIcon::ModIcon(uID3, hIcon, NULL);
    NotifyIcon::DelIcon(uID2);
    UINT uCookie = NotifyIcon::Attach(callbackFunc);
    NotifyIcon::Detach(uCookie);

    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0)) 
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

void callbackFunc(UINT uID, UINT message)
{
    if (message == WM_LBUTTONDOWN || message == WM_LBUTTONUP || message == WM_LBUTTONDBLCLK ||
        message == WM_RBUTTONDOWN || message == WM_RBUTTONUP || message == WM_RBUTTONDBLCLK)
    {
        WCHAR szDbg[256];
        ZeroMemory(szDbg,256);
        wsprintf(szDbg, L"[Dongyu] uID = %d, message = %x", uID, message);
        OutputDebugString(szDbg);
    }
}

参考文章:

http://www.nowamagic.net/librarys/veda/detail/227

原文地址:https://www.cnblogs.com/zuibunan/p/3895497.html