Рекурсивный цикл сообщений

У меня возникают проблемы с корректным запуском цикла обработки сообщений из обработчика сообщений. По сути, репликация того, как DialogBox() обрабатывает сообщения, за вычетом всех окон.

Простой вызов GetMessage() из обработчика сообщений почти работает, кроме случаев, когда событие WM_SYSKEYDOWN, открывающее системное меню, также запускает запись в подцикле. После того, как это происходит, происходит проглатывание нажатий клавиш и отправка сообщений WM_MOUSEMOVE относительно системного меню в главное окно.

Для записи это происходит как в Windows 8, так и в XP.

Чтобы дать некоторый контекст, я пытаюсь модель потоков, где рабочий поток (без окон) связывается посредством блокирования обратных вызовов SendMessage к главному окну, выступающему в роли сервера. Эти действия могут потребовать дополнительного ввода или зависеть от других операций ввода-вывода, поэтому обычные сообщения должны обрабатываться до тех пор, пока ответ не будет готов.

Я совершенно уверен, что это основная ошибка или недоразумение с моей стороны, точно так же, как в прошлый раз, когда я писал здесь, но я не могу понять, что я делаю неправильно самостоятельно.

Вот мой случай с репро. Попробуйте переместиться после нажатия 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 ответ

Модальные циклы сообщений прекрасно работают. У Раймонда Чена есть серия статей о правильном написании модальных циклов сообщений.

Я замечаю одну вещь: ваша ветка должна публиковать сообщение, а не отправлять его; SendMessage звонки прямо в окно проц. Не использовать PostThreadMessage, или; это предназначено для потоков без видимого пользовательского интерфейса (и вложенных DispatchMessage не будет знать, как отправить сообщение потока, что приведет к удалению сообщений).

Другие вопросы по тегам