Win32 托盘图标弹出菜单使用

简易对话框消息处理, 托盘图标显示, 弹出菜单显示(失去焦点自动关闭)

main.cpp

#include <windows.h>
#include <strsafe.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

INT_PTR WINAPI DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

#define WM_TRAYICON                 (WM_USER + 10)
const UINT WM_TASKBARCREATED = ::RegisterWindowMessage(_T("TaskbarCreated"));

int APIENTRY WinMain(
    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine,
    _In_ int nShowCmd)
{
    UNREFERENCED_PARAMETER(hInstance);
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(nShowCmd);

    DialogBox(::GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG), NULL, DialogProc);

    return 0;
}

// 添加托盘图标
void ShellNotifyIconAdd(HWND hWnd)
{
    NOTIFYICONDATA nid = { 0 };
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd = hWnd;
    nid.uID = 0;
    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.uCallbackMessage = WM_TRAYICON;
    nid.hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON));
    StringCchCopy(nid.szTip, _countof(nid.szTip), _T("Demo"));
    Shell_NotifyIcon(NIM_ADD, &nid);
}

// 删除托盘图标
void ShellNotifyIconDelete(HWND hWnd)
{
    NOTIFYICONDATA nid = { 0 };
    nid.cbSize = sizeof(nid);
    nid.hWnd = hWnd;
    nid.uID = 0;
    nid.uFlags = 0;
    Shell_NotifyIcon(NIM_DELETE, &nid);
}

// 显示弹出菜单
void ShowPopupMenu(HWND hWnd, int xPos, int yPos, bool isTop)
{
    MENUITEMINFO mii = { 0 };
    TCHAR szBuf[MAX_PATH] = { 0 };

    mii.cbSize = sizeof(mii);
    mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
    mii.fType = MFT_STRING | MFT_OWNERDRAW;
    mii.dwTypeData = szBuf;

    HMENU hMainMenu = ::GetMenu(hWnd);
    if (hMainMenu)
    {
        HMENU hPopMenu = ::CreatePopupMenu();
        int nCount = ::GetMenuItemCount(hMainMenu);
        for (int i = 0; i < nCount; i++)
        {
            mii.cch = _countof(szBuf);
            ::GetMenuItemInfo(hMainMenu, i, TRUE, &mii);
            ::InsertMenuItem(hPopMenu, i, TRUE, &mii);
        }

        ::TrackPopupMenuEx(hPopMenu,
            TPM_LEFTALIGN | (isTop ? TPM_BOTTOMALIGN : TPM_TOPALIGN),
            xPos,
            yPos,
            hWnd,
            NULL
        );
    }
}

bool ShowForeground(HWND hWnd)
{
    HWND hForeWnd = ::GetForegroundWindow();
    DWORD dwForeID = ::GetWindowThreadProcessId(hForeWnd, NULL);
    DWORD dwCurID = ::GetCurrentThreadId();
    ::AttachThreadInput(dwCurID, dwForeID, TRUE);
    BOOL isSuc = ::SetForegroundWindow(hWnd);
    ::AttachThreadInput(dwCurID, dwForeID, FALSE);

    if (isSuc)
    {
        //return true;
    }

    if (!::IsWindowVisible(hWnd))
    {
        ::ShowWindow(hWnd, SW_SHOW);
    }

    if (IsIconic(hWnd))
    {
        ::ShowWindow(hWnd, SW_SHOWNORMAL);
    }

    return ::SetForegroundWindow(hWnd);
}

INT_PTR WINAPI DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // 资源管理器重启后重新建立托盘图标
    if (WM_TASKBARCREATED == uMsg)
    {
        ShellNotifyIconAdd(hWnd);
    }

    // 消息处理
    switch (uMsg)
    {
    case WM_INITDIALOG:
    {
        ShellNotifyIconAdd(hWnd);
    }
    break;
    case WM_CLOSE:
    {
        ShellNotifyIconDelete(hWnd);
        ::EndDialog(hWnd, 0);
    }
    break;
    case WM_RBUTTONUP:
    {
        int xPos = ((int)(short)LOWORD(lParam));
        int yPos = ((int)(short)HIWORD(lParam));
        POINT pt = { xPos, yPos };
        ClientToScreen(hWnd, &pt);
        ShowPopupMenu(hWnd, pt.x, pt.y, false);
    }
    break;
    case WM_TRAYICON:
    {
        if (WM_LBUTTONDBLCLK == lParam)
        {
            ShowForeground(hWnd);
        }

        if (WM_RBUTTONUP == lParam)
        {
            // 防止托盘弹出菜单失去焦点后不消失
            static HWND hHideWnd = CreateWindowEx(0L,
                _T("Static"),
                _T(""),
                WS_CHILDWINDOW,
                0,
                0,
                0,
                0,
                HWND_MESSAGE,
                NULL,
                GetModuleHandle(NULL),
                NULL
            );

            if (hHideWnd && ::SetForegroundWindow(hHideWnd))
            {
                POINT pt = { 0 };
                ::GetCursorPos(&pt);
                ShowPopupMenu(hWnd, pt.x, pt.y, false);
            }
        }
    }
    break;
    case WM_COMMAND:
    {
        //消息源   HIWORD(wParam)      LOWORD(wParam)     lParam 
        //菜单     0                   菜单ID             0
        //快捷键   1                   快捷键ID           0
        //控件     控件定义的通知码    控件ID             控件窗口句柄
        UINT nNotify = HIWORD(wParam);
        UINT nID = LOWORD(wParam);
        HWND hWndFrom = (HWND)lParam;

        switch (nID)
        {
        case ID_FILE_EXIT:
        case IDOK:
        case IDCANCEL:
        {
            ::PostMessage(hWnd, WM_CLOSE, 0, 0);
        }
        }
    }
    break;
    default:
        return FALSE;
    }

    return TRUE;
}

托盘图标使用工程代码仓库

https://gitee.com/flame_cyclone/ShellNotifyIcon.git

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值