API NotifyIcon WinAPI, не отображается сообщение

102
12 марта 2021, 22:10

Я использую API NotifyIcon для показа сообщений (Baloon или уведомления в Win 10). Дело в том, что сообщение упорно не показывается на экран. Возвращаемое значение всегда истина, последнее сообщение от ошибке - 0 (однако я знаю, что функция Shell_NotifyIcon вызывает SetLastError(0), поэтому я не могу получить сообщение об ошибке). Я создал минимальный пример, который демонстрирует нужный мне функционал:

  1. Создает простейшее окно и добавляет его в область уведомлений(системный трей) + показывает соответствующее сообщение(которое не показывается)
  2. Создает контекстное меню, которое вызывается при нажати ПКМ по иконке в области уведомления
  3. В меню содержится единственная кнопка Click, которая показывает/скрывает окно в зависимости от его состояния, и, опять же - пытается показать сообщение(не показывает и все тут)
  4. При закрытии окна происходит уничтожение иконки в области уведомления, т.е. удаление из оного

Также, я добавил консоль, куда пишутся возвращаемые значения (для удобства). Вот код примера:

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
using namespace std;
#define MENU_TEST 10
#define RBUTTON_MENU WM_USER + 3000

void showMessage(HWND hwnd, const wchar_t* mes, int flag);
LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    SetConsoleOutputCP(1251);
    SetConsoleCP(1251);
    if (!AllocConsole())
        return -1;
    wcout.imbue(locale("rus_rus.866")); 
    wcin.imbue(locale("rus_rus.866")); 
    _wfreopen(L"CONOUT$", L"wt", stdout); 
    _wfreopen(L"CONIN$", L"rt", stdin); 
    HWND hwnd;
    MSG msg; 
    WNDCLASSEX wc; 
    wc.cbSize = sizeof(wc); 
    wc.style = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = wndProc; 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = L"test__class"; 
    wc.cbWndExtra = NULL; 
    wc.cbClsExtra = NULL; 
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); 
    wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 
    wc.hInstance = hInstance; 
    if (!RegisterClassEx(&wc)) 
        return -1; 
    hwnd = CreateWindow(L"test__class",     L"Test Notify", WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, NULL, CW_USEDEFAULT, NULL, (HWND)NULL, NULL, HINSTANCE(hInstance), NULL); 
    if (!hwnd)
        return -1;
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, NULL, NULL))
    { 
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
    return msg.wParam; 
}
void showMessage(HWND hwnd, const wchar_t* mes, int flag)
{
    NOTIFYICONDATA nid;
    static const GUID name  = { 0xaaaad36f, 0xd48a, 0x4306, { 0x84, 0x45, 0x73, 0x84, 0xc9, 0xf1, 0x3f, 0xa0 } };
    memset(&nid, 0, sizeof(NOTIFYICONDATA));
    nid.cbSize = sizeof(NOTIFYICONDATA);
    nid.hWnd = hwnd;
    nid.guidItem = name;
    nid.uID = 7;
    nid.uFlags = NIF_INFO | NIF_STATE | NIF_ICON | NIF_TIP | NIF_MESSAGE;
    nid.uCallbackMessage = RBUTTON_MENU;
    wcscpy_s(nid.szInfo, mes);
    nid.dwInfoFlags = NIIF_NOSOUND; 
    wcscpy_s(nid.szTip, L"Test");
    wcout << L"Message: " << mes << endl;
    wcout << L"Result function NotifyIcon: " << Shell_NotifyIcon(flag, &nid) << endl;
    wcout << L"Last error: " << GetLastError() << endl;
}
LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{
    static HMENU hMenu;
    switch (uMsg) 
    {
    case WM_CREATE: 
    {
        hMenu = CreatePopupMenu();
        AppendMenuA(hMenu, MF_STRING, MENU_TEST, "Click");
        showMessage(hwnd, L"App started", NIM_ADD);
        break;
    }
    case RBUTTON_MENU:
    {
        switch (lParam)
        {
        case WM_RBUTTONUP:
        {
            SetForegroundWindow(hwnd);
            POINT pt;
            GetCursorPos(&pt); 
            TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
            break;
        }
        default:
            break;
        }
    }
    case WM_COMMAND:
    {
        switch (LOWORD(wParam))
        {
        case MENU_TEST: 
        {
            bool visible = IsWindowVisible(hwnd);
            ShowWindow(hwnd, !visible ? SW_SHOW :SW_HIDE);
            showMessage(hwnd, !visible ? L"App restored" : L"App minimazed", NIM_MODIFY);
            break;
        }
        default: break;
        }
        break;
    }
    case WM_DESTROY: 
        showMessage(hwnd, L"App closed", NIM_DELETE);
        DestroyMenu(hMenu);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

Почему так происходит? Сообщение упорно не появляется..спасибо.

Answer 1

В таком варианте указанный GUID будет проигнорирован, так как отсутствует флаг NIF_GUID, видимо раз окно еще только в процессе создания комбинация hwnd + uID не прокатывает.

nid.uFlags = NIF_INFO | NIF_STATE | NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_GUID;

Далее, в wndProc имеется неопределенное поведение, так как функция может заканчиваться не возвращая никакого значения.

Проверка результата вызова функции тоже неправильная, GetLastError необходимо вызывать до вызова любых других функций winapi:

if(FALSE == Shell_NotifyIcon(flag, &nid))
{
    auto const last_error{GetLastError()};
    wcout << L"Shell_NotifyIcon failed with error #" << last_error << endl;
}
READ ALSO
Необработанное исключение по адресу 0x000000013F6B212B в FinalHope.exe: 0xC0000005: нарушение прав доступа при записи по адресу 0x00000000001C6000

Необработанное исключение по адресу 0x000000013F6B212B в FinalHope.exe: 0xC0000005: нарушение прав доступа при записи по адресу 0x00000000001C6000

Я использую memcpy для того чтобы скопировать в bytebuffer информацию из массиваВот простой код:

117
Как можно добавить функцию класса в LuaBridge

Как можно добавить функцию класса в LuaBridge

В функции инициализации функций для луа в моем классе, я бы хотел реализовать регистрацию функции из самого класса и что бы она выполнялась...

124
как сделать свой тип в c++?

как сделать свой тип в c++?

Например я могу сделать в структуре или в классе вот так

86
Воспроизведение аудиофайла в Jquery

Воспроизведение аудиофайла в Jquery

Всем приветКак реализовать в Jquery, чтобы при каждом клике аудиофайл проигрывался всего один раз

114