2

我无法从消息处理程序中正确运行消息循环。实际上复制 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;
}
4

1 回答 1

1

模态消息循环非常好。Raymond Chen 有一系列关于正确编写模态消息循环的文章

我注意到一件事:您的线程应该发布消息,而不是发送消息;SendMessage直接调用窗口过程。也不要使用PostThreadMessage;这是为没有可见 UI 的线程设计的(并且嵌套DispatchMessage的线程不知道如何调度线程消息,从而导致消息丢失)。

于 2013-10-12T19:17:04.577 回答