为什么 GetMessage 退出我的程序而不发送任何消息?
Why is GetMessage exiting my program without sending any message?
这是我的问题。我正在尝试创建一个仍然使用 trayIcon 和 Hooks 的 windowless 程序,所以我需要使用消息(或不使用消息?)但是当我使用它们时,我不知道如何释放我的内存杀死我的进程。甚至 类 的析构函数也不会被调用。这是一个主要的测试:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pCmdLine, int nCmdShow)
{
MSG msg;
OutputDebugStringW(L"Start.\n");
while (GetMessageW(&msg, NULL, NULL, NULL) > 0)
{
OutputDebugStringW(L"one.\n");
TranslateMessage(&msg);
OutputDebugStringW(L"two.\n");
DispatchMessage(&msg);
OutputDebugStringW(L"three.\n");
}
OutputDebugStringW(L"end.\n");
return 0;
}
正如我在文档中看到的那样,GetMessage()
调用应该 return 0 或更少才能退出,但是当我 运行 它然后关闭它时,我只得到"Start." 日志,我不明白为什么。如果没有办法通过这个循环,那么我该如何调用我的析构函数呢?我的 trayIcon 确实有一个 window,它没有收到任何消息,也许我应该将它作为参数传递给 GetMessage()
?
PS:我的项目使用 trayIcons 和 Hooks,当我使用相同的调试打印 运行 它时,它显示一次前 4 个字符串,但在关闭时什么也没有,甚至 "end." 字符串.
编辑:我的(糟糕的)trayIcon 创建:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
OutputDebugStringW(L"Message!\n");
switch (uMsg)
{
case WM_DESTROY:
OutputDebugStringW(L"Close message received\n");
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
case WM_RBUTTONUP:
{
OutputDebugStringW(L"Trying to open Context menu\n");
POINT const pt = { LOWORD(wParam), HIWORD(wParam) };
break;
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
bool CreateNotifyIcon(HINSTANCE& hInstance)
{
NOTIFYICONDATA notif = {};
static const wchar_t class_name[] = L"ExtendClass";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WindowProc;
wx.hInstance = hInstance;
wx.lpszClassName = class_name;
RegisterClassEx(&wx);
HWND win = CreateWindowEx(0, class_name, L"Windows Extend", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (win == NULL)
OutputDebugStringW(L"failed to create window\n");
ZeroMemory(¬if, sizeof(NOTIFYICONDATA));
notif.cbSize = sizeof(NOTIFYICONDATA);
notif.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
// Need to find a non-busy uID
notif.uID = 44421;
notif.hWnd = win;
StringCchCopy(notif.szTip, ARRAYSIZE(notif.szTip), L"Access Windows Extend options.");
StringCchCopy(notif.szInfo, ARRAYSIZE(notif.szInfo), L"Access Windows Extend options.");
StringCchCopy(notif.szInfoTitle, ARRAYSIZE(notif.szInfoTitle), L"Windows Extend");
notif.hIcon = (HICON)LoadImage(NULL, L"./Luma.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (!Shell_NotifyIcon(NIM_ADD, ¬if))
{
OutputDebugStringW(L"failed to create notifIcon\n");
return false;
}
return true;
}
GetMessage
returns -1 如果发生错误。所以你一般应该做 while != 0
。但是,如果您没有看到 "end",那么您的应用程序可能正在崩溃。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx
GetMessage()
在收到 window/thread 消息或有消息要合成之前不会 return。在您显示的代码中,您没有创建任何 windows,没有向自己发布任何线程消息,也没有创建任何需要消息循环的挂钩,因此 GetMessage()
无事可做。它被无限期地阻止。这就是为什么在您强行终止程序之前,您只会看到您的开始消息而不会发生任何其他事情的原因。
由于您打算显示系统托盘图标,因此需要一个 window,即使只是一个隐藏的 window,以便接收有关用户与图标交互的通知。您的 GetMessage()
循环将处理在与循环相同的线程中创建的 all windows 的消息,因为您将 hWnd
参数设置为 NULL 具体 window。一旦你创建了托盘图标window,循环就会很好地接收它的消息。然后,您可以为您的托盘图标提供一个弹出菜单,其中包含一个项目,单击该项目将退出您的消息循环,从而允许您优雅地退出 WinMain()
、调用析构函数等
这是我的问题。我正在尝试创建一个仍然使用 trayIcon 和 Hooks 的 windowless 程序,所以我需要使用消息(或不使用消息?)但是当我使用它们时,我不知道如何释放我的内存杀死我的进程。甚至 类 的析构函数也不会被调用。这是一个主要的测试:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pCmdLine, int nCmdShow)
{
MSG msg;
OutputDebugStringW(L"Start.\n");
while (GetMessageW(&msg, NULL, NULL, NULL) > 0)
{
OutputDebugStringW(L"one.\n");
TranslateMessage(&msg);
OutputDebugStringW(L"two.\n");
DispatchMessage(&msg);
OutputDebugStringW(L"three.\n");
}
OutputDebugStringW(L"end.\n");
return 0;
}
正如我在文档中看到的那样,GetMessage()
调用应该 return 0 或更少才能退出,但是当我 运行 它然后关闭它时,我只得到"Start." 日志,我不明白为什么。如果没有办法通过这个循环,那么我该如何调用我的析构函数呢?我的 trayIcon 确实有一个 window,它没有收到任何消息,也许我应该将它作为参数传递给 GetMessage()
?
PS:我的项目使用 trayIcons 和 Hooks,当我使用相同的调试打印 运行 它时,它显示一次前 4 个字符串,但在关闭时什么也没有,甚至 "end." 字符串.
编辑:我的(糟糕的)trayIcon 创建:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
OutputDebugStringW(L"Message!\n");
switch (uMsg)
{
case WM_DESTROY:
OutputDebugStringW(L"Close message received\n");
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
case WM_RBUTTONUP:
{
OutputDebugStringW(L"Trying to open Context menu\n");
POINT const pt = { LOWORD(wParam), HIWORD(wParam) };
break;
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
bool CreateNotifyIcon(HINSTANCE& hInstance)
{
NOTIFYICONDATA notif = {};
static const wchar_t class_name[] = L"ExtendClass";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WindowProc;
wx.hInstance = hInstance;
wx.lpszClassName = class_name;
RegisterClassEx(&wx);
HWND win = CreateWindowEx(0, class_name, L"Windows Extend", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (win == NULL)
OutputDebugStringW(L"failed to create window\n");
ZeroMemory(¬if, sizeof(NOTIFYICONDATA));
notif.cbSize = sizeof(NOTIFYICONDATA);
notif.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
// Need to find a non-busy uID
notif.uID = 44421;
notif.hWnd = win;
StringCchCopy(notif.szTip, ARRAYSIZE(notif.szTip), L"Access Windows Extend options.");
StringCchCopy(notif.szInfo, ARRAYSIZE(notif.szInfo), L"Access Windows Extend options.");
StringCchCopy(notif.szInfoTitle, ARRAYSIZE(notif.szInfoTitle), L"Windows Extend");
notif.hIcon = (HICON)LoadImage(NULL, L"./Luma.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (!Shell_NotifyIcon(NIM_ADD, ¬if))
{
OutputDebugStringW(L"failed to create notifIcon\n");
return false;
}
return true;
}
GetMessage
returns -1 如果发生错误。所以你一般应该做 while != 0
。但是,如果您没有看到 "end",那么您的应用程序可能正在崩溃。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx
GetMessage()
在收到 window/thread 消息或有消息要合成之前不会 return。在您显示的代码中,您没有创建任何 windows,没有向自己发布任何线程消息,也没有创建任何需要消息循环的挂钩,因此 GetMessage()
无事可做。它被无限期地阻止。这就是为什么在您强行终止程序之前,您只会看到您的开始消息而不会发生任何其他事情的原因。
由于您打算显示系统托盘图标,因此需要一个 window,即使只是一个隐藏的 window,以便接收有关用户与图标交互的通知。您的 GetMessage()
循环将处理在与循环相同的线程中创建的 all windows 的消息,因为您将 hWnd
参数设置为 NULL 具体 window。一旦你创建了托盘图标window,循环就会很好地接收它的消息。然后,您可以为您的托盘图标提供一个弹出菜单,其中包含一个项目,单击该项目将退出您的消息循环,从而允许您优雅地退出 WinMain()
、调用析构函数等