У меня возникли проблемы с правильной работой цикла сообщений из обработчика сообщений. В действительности реплицирует, как 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;
}
не делайте этого, вы будете сталкиваться только с проблемами один за другим. Если вам нужно сотрудничество потоков, вы можете использовать PostMessage/PostThreadMessage (с окном объекта или без него в рабочем потоке) – manuell
Спасибо, я попробую обходное решение. Меня все еще беспокоит, что я не понимаю операции очереди сообщений после всех этих лет. Можете ли вы дать мне какие-либо подсказки относительно того, почему это не удается или какая часть контракта я нарушаю? – doynax
Я не знаю, вероятно, связан с запуском нового цикла сообщений, пока предыдущий DispatchMessage() все еще работает. Лично я бы использовал ожидающее событие через 'CreateEvent()' вместо этого. Посмотрите на связанные функции, такие как 'SetEvent()', 'ResetEvent()', 'PulseEvent()' и 'WaitForSingleObject()'. –