我正在使用 NotifyIcon API 来显示消息(Baloon 或 Win 10 上的通知)。问题是消息没有显示在屏幕上。返回值始终为true,最后一条错误信息为0(不过,我知道Shell_NotifyIcon函数调用了SetLastError(0),所以无法得到错误信息)。我创建了一个最小的示例来演示我需要的功能:
- 创建一个简单的窗口并将其添加到通知区域(系统托盘)+显示相应的消息(未显示)
- 创建一个右键单击通知区域中的图标时调用的上下文菜单
- 该菜单包含一个单击按钮,该按钮根据其状态显示/隐藏窗口,并且再次尝试显示一条消息(不显示,仅此而已)
- 当窗口关闭时,通知区域的图标被销毁,即 从中移除
另外,我添加了一个控制台,其中写入了返回值\u200b\u200bare(为方便起见)。这是示例代码:
#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);
}
}
为什么会这样?该消息顽固地没有出现..谢谢。
在这个变体中,指定的 GUID 将被忽略,因为 flag is missing
NIF_GUID
,显然由于窗口仍在创建过程中,hwnd + uID 组合不起作用。此外,
wndProc
还有未定义的行为,因为函数可以结束而不返回任何值。检查函数调用的结果也是错误的,
GetLastError
必须在调用任何其他 winapi 函数之前调用它: