c++ - WM_QUIT 只发布线程而不是窗口?

标签 c++ windows winapi message-queue

在 Windows API 中,我正在研究 GetMessage 函数的实际工作原理。我已经看到了 Windows 消息循环的 3 个实现,并且想探索它们。


1)

截至撰写本文时,this MSDN article描述了我认为是实现消息循环的正确方法。

MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
} 


2)

关于 GetMessage function page ,我看到了这个实现:

MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}


3)

最后,Visual Studio documentation将此实现作为其 Win32 应用程序演示的一部分。

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


讨论

简而言之,实现 #3 忽略了从 GetMessage 返回的错误,但在其他方面与第一个实现相同。也就是说,它们都处理当前线程的所有消息。当 GetMessage 函数返回 0 时,循环终止。

因为我在 #1 之前找到了实现 #2,所以我认为它已经完成了。但是,我注意到当通过 PostQuitMessage 发布 WM_QUIT 消息时,GetMessage 不会返回 0

这导致了一些困惑,直到我找到实现 #1 并对其进行了测试。前两个实现的区别在于 GetMessage 的第二个参数。在 #2 中,它指定了 hWnd,根据 GetMessage 文档,它是:

A handle to the window whose messages are to be retrieved. The window must belong to the current thread.

在 #1 中,它是 NULL,属于此摘录:

If hWnd is NULL, GetMessage retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL (see the MSG structure). Therefore if hWnd is NULL, both window messages and thread messages are processed.

当使用NULL进行测试时,GetMessage函数在处理完WM_QUIT消息时返回0,成功终止循环。

问题

  1. 即使 PostQuitMessage 是从特定窗口的回调函数调用的,WM_QUIT 是否真的属于该窗口或当前线程?根据对这三个实现的测试,它似乎与当前线程相关联。

  2. 如果与线程关联,何时使用有效的hWnd 作为GetMessage 的参数有用或合适?这样的消息循环将无法返回 0 作为对 WM_QUIT 的 react ,那么有没有其他方法可以终止消息循环?

引用资料

代码

#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int nCmdShow) {
    LPCTSTR wndClassName =_T("Class_SHTEST");
    LPCTSTR wndName = _T("SHTest");

    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW|CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wcex.hbrBackground = (HBRUSH) COLOR_WINDOW+1;
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = wndClassName;
    wcex.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL, _T("Call to RegisterClassEx failed!"), wndName, MB_OK|MB_ICONERROR);
    }

    HWND window = CreateWindow(wndClassName, wndName,
        WS_OVERLAPPEDWINDOW | WS_MAXIMIZE, 
        0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL);
    if (!window) {
        MessageBox(NULL, _T("Call to CreateWindow failed!"), wndName, MB_OK|MB_ICONERROR);
    }

    ShowWindow(window, SW_SHOW);
    UpdateWindow(window);

    //Message loop (using implementation #1)
    MSG msg;
    BOOL bRet;
    while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            //Handle error and possibly exit.
        }
        else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    //Return the exit code in the WM_QUIT message.
    return (int) msg.wParam;
}

最佳答案

根据 MSDN documention WM_QUIT:

The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure. It is retrieved only by the GetMessage or PeekMessage functions.

由于 WM_QUIT 不与窗口相关联,并且将 HWND 传递给 GetMessage() 仅检索与该窗口相关联的那些消息,后者在设计上永远不会收到 WM_QUIT

至于何时您希望将 HWND 传递给 GetMessage(),在应用程序的一般消息循环中您不会这样做。但有时您希望在 UI 中发生某些事情时发送消息,并且只关心与特定窗口关联的消息。

关于c++ - WM_QUIT 只发布线程而不是窗口?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32768924/

相关文章:

.net - 安装后 MSI 文件复制到哪里?

windows - 使用 Moovweb 时 Windows 出现权限被拒绝(公钥)错误

c++ - 创建类似目录树的 Windows 资源管理器

c++ - 需要帮助调试从 const char* 到 char* [-fpermissive] 的无效转换

c++ - 为什么 C++ 标准库与编译器而不是操作系统捆绑在一起?

c - 将连接重定向到 C 中指定本地端口的服务器应用程序

windows - Windows 上的 OpenGL 1.0 和 1.1 函数指针

c++ - 在文本编辑器显示链中使用双缓冲有多大意义?

C++ 模板参数 T(*)[]

c++ - apache thrift,序列化未签名