c++ - 系统托盘上下文菜单空白

标签 c++ windows system-tray

我正在尝试创建一个没有可见窗口的应用程序,只有一个托盘图标。我试图在这里拼凑各种教程和答案,但无法取得比这更进一步的结果。右键单击时出现上下文菜单,但完全空白。我也不确定一旦它开始工作,我将如何检测我点击的内容。

最终目标是能够通过单击上下文菜单中的两个选项之一来切换 DNS 服务器。

#include <Windows.h>
#include <shellapi.h>
#include <tchar.h>
#include <WinUser.h>


HINSTANCE gInstance = NULL;

LRESULT CALLBACK pWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wx;
    HWND hWnd;
    ZeroMemory(&wx, sizeof(WNDCLASSEX));

    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = pWndProc;
    wx.hInstance = hInstance;
    wx.lpszClassName = (LPCWSTR)"DNSChanger";
    RegisterClassEx(&wx);
    CreateWindowEx(0, (LPCWSTR)"DNSChanger", (LPCWSTR)"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
    gInstance = hInstance;

    MSG stMsg;
    while (GetMessage(&stMsg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&stMsg);
        DispatchMessage(&stMsg);
    }

    return 0;
}

LRESULT CALLBACK pWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    NOTIFYICONDATA niData;
    ZeroMemory(&niData, sizeof(NOTIFYICONDATA));

    switch (uMsg)
    {
        case WM_CREATE:
        {
            niData.cbSize = sizeof(NOTIFYICONDATA);
            niData.uID = 1;
            niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
            niData.hIcon = LoadIcon(gInstance, MAKEINTRESOURCE(IDI_SHIELD));
            niData.hWnd = hWnd;
            niData.uCallbackMessage = WM_USER + 1;

            Shell_NotifyIcon(NIM_ADD, &niData);
        }
        return 0;

        case WM_DESTROY:
        {
            niData.hWnd = hWnd;
            Shell_NotifyIcon(NIM_DELETE, &niData);
        }
        return 0;

        case WM_USER + 1:
        {
            switch (LOWORD(lParam))
            {
                case WM_RBUTTONUP:
                {
                    POINT lpClickPoint;
                    HMENU hPopMenu;

                    UINT uFlag = MF_BYPOSITION | MF_UNCHECKED | MF_STRING;
                    GetCursorPos(&lpClickPoint);
                    hPopMenu = CreatePopupMenu();
                    InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, WM_USER + 1, _T("Exit"));
                    SetForegroundWindow(hWnd);
                    TrackPopupMenu(hPopMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y, 0, hWnd, NULL);
                }
            }
        }
    }
}

最佳答案

不要像这样使用转换 (LPCWSTR)"DNSChanger"。这只会隐藏编译器错误。您的程序能够正常运行的唯一原因是因为此错误在 2 个不同的地方重复出现并且被抵消了。

您打算编写 L"DNSChanger"

窗口过程必须返回 DefWindowProc(hWnd, uMsg, wParam, lParam);

如果要关闭应用程序,在 WM_DESTROY 中必须包含 PostQuitMessage(0);

定义一个在菜单中使用的新常量

const int IDM_EXIT = 100;
...
InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit");

菜单将发送 IDM_EXIT 命令作为 WM_COMMAND 消息的一部分。以下是一些建议的更改:

HINSTANCE gInstance = NULL;
const int IDM_EXIT = 100;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static NOTIFYICONDATA niData = { sizeof(NOTIFYICONDATA) };

    switch(uMsg)
    {
    case WM_CREATE:
    {
        niData.uID = 1;
        niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
        niData.hIcon = LoadIcon(gInstance, IDI_SHIELD);
        niData.hWnd = hWnd;
        niData.uCallbackMessage = WM_USER + 1;
        Shell_NotifyIcon(NIM_ADD, &niData);
        return 0;
    }

    case WM_DESTROY:
    {
        niData.hWnd = hWnd;
        Shell_NotifyIcon(NIM_DELETE, &niData);
        PostQuitMessage(0);
        return 0;
    }

    case WM_COMMAND:
    {
        if(LOWORD(wParam) == IDM_EXIT)
            PostQuitMessage(0);
        break;
    }

    case WM_USER + 1: 
    {
        WORD cmd = LOWORD(lParam);
        if (cmd == WM_RBUTTONUP || cmd == WM_LBUTTONUP)
        {
            POINT pt;
            GetCursorPos(&pt);
            HMENU hmenu = CreatePopupMenu();
            InsertMenu(hmenu, 0, MF_BYPOSITION | MF_STRING, IDM_EXIT, L"Exit");
            TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, pt.x, pt.y, 0, hWnd, NULL);
        }
        break;
    }

    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
    gInstance = hInstance;
    WNDCLASSEX wx = { sizeof(WNDCLASSEX) };
    wx.lpfnWndProc = WndProc;
    wx.hInstance = hInstance;
    wx.lpszClassName = L"DNSChanger";
    RegisterClassEx(&wx);

    CreateWindowEx(0, L"DNSChanger", L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);

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

关于c++ - 系统托盘上下文菜单空白,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47223543/

相关文章:

python - QT 系统托盘应用程序中的更新菜单

c++ - 所有 std::tuple 构造函数都是必需的吗?

c++ - 在可变参数模板中传递参数组

javascript - Windows 10 上的 Electron 托盘图标问题

c++ - SMBIOS 枚举值。文档错误?

c - 是否可以在不复制的情况下删除大文件的两端?

windows - 当应用程序失去焦点时,Qt 系统托盘上下文菜单仍然存在

C++:使用 pthread_create 创建新线程,以运行类成员函数

c++ - 如何测试是否删除了 boost 共享内存对象?

python - 为什么[Errno 13]权限被拒绝?