如何按需显示shell通知图标气球工具提示?

时间:2015-10-17 15:46:45

标签: c++ winapi notifyicon balloon-tip

我的目标是创建一个shell通知图标,并在需要时显示一个气球工具提示。我写了下面的代码。

bool SystemTrayIcon::Create(const std::wstring &    Tip,
                            HWND                    hWndParent,
                            const GUID &            Guid,
                            UINT                    IdCallback,
                            HICON                   hIcon,
                            TYPE                    Type,
                            bool                    bSound,
                            bool                    bSharedIcon,
                            bool                    bHidden,
                            bool                    bLargeIcon,
                            bool                    bRespectQuiteTime)
{
    NotifyIconData.cbSize           = sizeof(NotifyIconData);
    NotifyIconData.hWnd             = hWndParent;
    NotifyIconData.uID              = 0;    // Use GUID instead. (NIF_GUID)
    NotifyIconData.uFlags           = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_STATE | NIF_GUID | NIF_REALTIME | NIF_SHOWTIP;
    NotifyIconData.uCallbackMessage = IdCallback;
    NotifyIconData.hIcon            = hIcon;

    if (Tip.length() > MAX_TIP)
    {
        std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), MAX_TIP);
        NotifyIconData.szTip[MAX_TIP] = wchar_t(0);
    }
    else
    {
        std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), Tip.length() + 1);
    }

    NotifyIconData.dwState          = (bSharedIcon      ? NIS_SHAREDICON    : 0)
                                    | (bHidden          ? NIS_HIDDEN        : 0);
    NotifyIconData.dwStateMask      = NIS_SHAREDICON | NIS_HIDDEN;
    NotifyIconData.uVersion         = NOTIFYICON_VERSION_4;

    DWORD dwType;
    switch (Type)
    {
        case TYPE::STI_INFO:
            dwType = NIIF_INFO;
            break;
        case TYPE::STI_WARNING:
            dwType = NIIF_WARNING;
            break;
        case TYPE::STI_ERROR:
            dwType = NIIF_ERROR;
            break;
    }

    NotifyIconData.dwInfoFlags      = dwType | NIIF_USER
                                    | (bSound               ? 0                         :   NIIF_NOSOUND)
                                    | (bLargeIcon           ? NIIF_LARGE_ICON           :   0)
                                    | (bRespectQuiteTime    ? NIIF_RESPECT_QUIET_TIME   :   0);

    NotifyIconData.guidItem         = Guid;

    return bInitialized = Shell_NotifyIconW(NIM_ADD, &NotifyIconData);
}

void SystemTrayIcon::Balloon(   const std::wstring &    Title,
                                const std::wstring &    Message,
                                HICON                   hBalloonIcon)
{
    if (!bInitialized) return;
    if (Title.length() > MAX_TITLE)
    {
        std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), MAX_TITLE);
        NotifyIconData.szInfoTitle[MAX_TITLE] = wchar_t(0);
    }
    else
    {
        std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), Title.length() + 1);
    }
    if (Message.length() > MAX_MESSAGE)
    {
        std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), MAX_MESSAGE);
        NotifyIconData.szInfo[MAX_MESSAGE] = wchar_t(0);
    }
    else
    {
        std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), Message.length() + 1);
    }
    NotifyIconData.hBalloonIcon = hBalloonIcon;
    NotifyIconData.dwInfoFlags |= NIF_INFO;
    Update();
}

void SystemTrayIcon::Update()
{
    Shell_NotifyIconW(NIM_MODIFY, &NotifyIconData);
}

我在这样的代码中调用这些成员函数:

TrayIcon.Create(/*const std::wstring &  Tip*/               L"Tip",
                /*HWND                  hWndParent*/        Window.hWnd,
                /*const GUID &          Guid*/              GUID {0x7f0f02e3, 0x479b, 0x4a09, {0xbf, 0x99, 0xd3, 0x39, 0xe9, 0x3a, 0x8b, 0x22}},
                /*UINT                  IdCallback*/        ID_TRAYICON,
                /*HICON                 hIcon*/             (HICON) LoadImageW(Status::hInstance, L"icon1.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE),
                /*TYPE                  Type*/              SystemTrayIcon::TYPE::STI_INFO,
                /*bool                  bSound*/            true,
                /*bool                  bSharedIcon*/       false,
                /*bool                  bHidden*/           false,
                /*bool                  bLargeIcon*/        true,
                /*bool                  bRespectQuiteTime*/ false);
Sleep(10000);
TrayIcon.Balloon(   L"New Title",
                    L"New Message",
                    (HICON) LoadImageW(Status::hInstance, L"icon2.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE));

调用Create()方法后,图标显示正确。但Balloon()方法无效。没有显示气球顶尖。

我可以通过将NIF_INFO常量添加到uFlags并填充szInfoTitleszInfo成员,使其在创建时显示气球。但我想要实现的是通过调用Balloon()方法在任意时间显示它。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

我在代码中解决了很多问题。现在它工作得非常好,正如我所希望的那样。以下是我的新代码。请注意更改。

bool SystemTrayIcon::Create(const std::wstring &    Tip,
                            HWND                    hWndParent,
                            const GUID &            Guid,
                            UINT                    IdCallback,
                            HICON                   hIcon,
                            bool                    bSharedIcon,
                            bool                    bHidden)
{
    if (bInitialized) return false;

    NotifyIconData.cbSize           = sizeof(NotifyIconData);
    NotifyIconData.hWnd             = hWndParent;
    NotifyIconData.uID              = 0;    // Use GUID instead. (NIF_GUID)
    NotifyIconData.uFlags           = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_STATE | NIF_GUID | NIF_SHOWTIP;
    NotifyIconData.uCallbackMessage = IdCallback;
    NotifyIconData.hIcon            = hIcon;

    if (Tip.length() > MAX_TIP)
    {
        std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), MAX_TIP);
        NotifyIconData.szTip[MAX_TIP] = wchar_t(0);
    }
    else
    {
        std::wcsncpy(NotifyIconData.szTip, Tip.c_str(), Tip.length() + 1);
    }

    NotifyIconData.dwState          = (bSharedIcon      ? NIS_SHAREDICON    : 0)
                                    | (bHidden          ? NIS_HIDDEN        : 0);
    NotifyIconData.dwStateMask      = NIS_SHAREDICON | NIS_HIDDEN;

    NotifyIconData.guidItem         = Guid;

    bInitialized = Shell_NotifyIconW(NIM_ADD, &NotifyIconData);

    NotifyIconData.uVersion         = NOTIFYICON_VERSION_4;
    bLastResult = Shell_NotifyIconW(NIM_SETVERSION, &NotifyIconData);

    return bInitialized;
}

void SystemTrayIcon::Balloon(   const std::wstring &    Title,
                                const std::wstring &    Message,
                                HICON                   hBalloonIcon,
                                BALLOON_ICON_TYPE       IconType,
                                UINT                    Timeout,    // In milliseconds.
                                bool                    bSound,
                                bool                    bLargeIcon,
                                bool                    bRespectQuiteTime)
{
    if (!bInitialized) return;

    if (Title.length() > MAX_TITLE)
    {
        std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), MAX_TITLE);
        NotifyIconData.szInfoTitle[MAX_TITLE] = wchar_t(0);
    }
    else
    {
        std::wcsncpy(NotifyIconData.szInfoTitle, Title.c_str(), Title.length() + 1);
    }

    if (Message.length() > MAX_MESSAGE)
    {
        std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), MAX_MESSAGE);
        NotifyIconData.szInfo[MAX_MESSAGE] = wchar_t(0);
    }
    else
    {
        std::wcsncpy(NotifyIconData.szInfo, Message.c_str(), Message.length() + 1);
    }

    DWORD dwType;
    switch (IconType)
    {
        case BALLOON_ICON_TYPE::BIT_NONE:
            dwType = 0;
            break;
        case BALLOON_ICON_TYPE::BIT_INFO:
            dwType = NIIF_INFO;
            break;
        case BALLOON_ICON_TYPE::BIT_WARNING:
            dwType = NIIF_WARNING;
            break;
        case BALLOON_ICON_TYPE::BIT_ERROR:
            dwType = NIIF_ERROR;
            break;
        case BALLOON_ICON_TYPE::BIT_USER_DEFINED:
            dwType = NIIF_USER; // Use the "hBalloonIcon" parameter.
            break;
    }

    NotifyIconData.dwInfoFlags      = dwType
                                    | (bSound               ? 0                         :   NIIF_NOSOUND)
                                    | (bLargeIcon           ? NIIF_LARGE_ICON           :   0)
                                    | (bRespectQuiteTime    ? NIIF_RESPECT_QUIET_TIME   :   0);

    NotifyIconData.uTimeout     = Timeout;
    NotifyIconData.hBalloonIcon = hBalloonIcon;
    NotifyIconData.uFlags       = NIF_INFO | NIF_GUID;

    Update();
}

void SystemTrayIcon::Update()
{
    bLastResult = Shell_NotifyIconW(NIM_MODIFY, &NotifyIconData);
}

代码中的用法:

TrayIcon.Create(/*const std::wstring &  Tip*/               L"Tip",
                /*HWND                  hWndParent*/        Window.hWnd,
                /*const GUID &          Guid*/              GUID {0x7f0f02e4, 0x479b, 0x4a09, {0xbf, 0x99, 0xd3, 0x39, 0xe9, 0x3a, 0x8b, 0x22}},
                /*UINT                  IdCallback*/        ID_TRAYICON,
                /*HICON                 hIcon*/             (HICON) hImage,
                /*bool                  bSharedIcon*/       false,
                /*bool                  bHidden*/           false);

// ...

TrayIcon.Balloon(   L"Button 2",
                    L"You have just clicked the Button #2.",
                    (HICON) hImage,
                    SystemTrayIcon::BALLOON_ICON_TYPE::BIT_USER_DEFINED,
                    20000U,
                    true,
                    true,
                    false);