递归消息循环

时间:2013-10-12 14:04:17

标签: winapi asynchronous modal-dialog message-queue systemmenu

我无法在消息处理程序中正确运行消息循环。实际上,复制DialogBox()如何处理消息,减去所有窗口。

从消息处理程序中调用GetMessage()几乎可以正常工作,除非打开系统菜单的WM_SYSKEYDOWN事件也触发进入子循环。在发生这种奇怪的事情之后,吞下按键并将相对于系统菜单的WM_MOUSEMOVE消息发送到主窗口。

对于记录,这在Windows 8和XP中都会发生。

为了给出一些上下文,我正在尝试一个线程模型,其中(无窗口)工作线程通过阻止SendMessage调用回到充当服务器的主窗口进行通信。这些操作可能需要进一步输入或依赖于其他I / O,因此需要处理常规消息,直到答复准备就绪。

我相当肯定这是我的一个基本错误或误解,就像我上次发布在这里一样,但我似乎无法弄清楚我自己做错了什么。

这是我的复制案例。按ALT + SPACE打开系统菜单后尝试导航

#include <windows.h>

BOOL update;

LRESULT WINAPI WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    MSG msg;
    char text[256];
    switch(uMsg) {
    case WM_DESTROY:
        ExitProcess(0);
    // Trigger an update on input
    case WM_SYSKEYDOWN:
        update = TRUE;
        break;
    // Display the update from the worker thread, returning once it is time to
    // ask for the next one
    case WM_USER:
        wsprintf(text, TEXT("%u"), (unsigned int) lParam);
        SetWindowText(hwnd, text);
        while(!update && GetMessage(&msg, NULL, 0, 0) > 0) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        update = FALSE;
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

DWORD WINAPI ThreadProc(void *hwnd) {
    // Submit updates as quickly as possible
    LONG sequence = 1;
    for(;;)
        SendMessage(hwnd, WM_USER, 0, sequence++);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCommandLine, int nCmdShow) {
    HWND hwnd;
    MSG msg;

    // Create our window
    WNDCLASS windowClass = { 0 };
    windowClass.lpfnWndProc = WindowProc;
    windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    windowClass.hCursor = NULL;
    windowClass.lpszClassName = TEXT("Repro");
    RegisterClass(&windowClass);
    hwnd = CreateWindow(TEXT("Repro"), TEXT("Repro"),
        WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
        hInstance, 0);
    // Launch the worker thread
    CreateThread(NULL, 0, ThreadProc, hwnd, 0, NULL);
    // And run the primary message loop
    while(GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

1 个答案:

答案 0 :(得分:1)

模态消息循环非常好。 Raymond Chen有series of articles on writing modal message loops properly

我注意到一件事:你的帖子应发布消息,而不是发送消息; SendMessage直接调用窗口proc。也不要使用PostThreadMessage;这是为没有可见UI(和nested DispatchMessage won't know how to dispatch the thread message的线程而设计的,导致丢弃的消息)。