为什么GetMessage退出我的程序而不发送任何消息?

时间:2017-10-26 22:51:25

标签: c++ windows msdn

这是我的问题。我试图创建一个仍然使用trayIcon和Hooks的无窗口程序,所以我需要使用消息(或不是?)但是当我使用它们时,我不知道如何在我杀死时释放我的记忆我的过程。即使是课程的破坏者也不会被召唤。这是一个测试主要:

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()调用应返回0或更少以退出,但是当我运行它,然后关闭它时,我只得到"开始。&#34 ;记录,我不明白为什么。如果没有办法通过这个循环,那我怎么称呼我的析构函数?我的trayIcon窗口没有收到任何消息,也许我应该把它作为参数传递给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(&notif, 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, &notif))
    {
        OutputDebugStringW(L"failed to create notifIcon\n");
        return false;
    }
    return true;
}

2 个答案:

答案 0 :(得分:3)

GetMessage()在收到窗口/线程消息或有合成消息之前不会返回。在您显示的代码中,您没有创建任何窗口,也没有向自己发布任何线程消息,也没有创建任何需要消息循环的挂钩,因此GetMessage()没有任何内容可以执行。它被无限期阻止。这就是为什么你只看到你的开始信息而没有其他事情发生,直到你强行杀死该程序。

由于您打算显示系统托盘图标,因此您需要一个窗口,即使只是一个隐藏的窗口,也需要有关用户与图​​标交互的通知。您的GetMessage()循环将处理在与循环相同的线程中创建的所有窗口的消息,因为您将hWnd参数设置为NULL而不是特定< / em>窗口。创建托盘图标窗口后,循环将接收到正确的消息。然后,您可以为托盘图标提供一个弹出菜单,其中包含一个项目,该项目将在单击时退出您的消息循环,从而允许您优雅地退出WinMain(),调用析构函数等。

答案 1 :(得分:0)

如果发生错误,

GetMessage将返回-1。所以你应该一般while != 0。但如果您没有看到“结束”,那么您的应用程序可能会崩溃。

https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx