From: Dmitry Timoshkov Subject: [2/3] user32: Add some tests for EndDialog called from other thread. Message-Id: <20150430180405.dca8f0cd.dmitry@baikal.ru> Date: Thu, 30 Apr 2015 18:04:05 +0800 These tests pass under Wine. Testbot failures are not related to this patch. --- dlls/user32/tests/msg.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index f2ba805..2b054ab 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -14869,6 +14869,117 @@ todo_wine flush_sequence(); } +static const struct message end_dialog_1[] = { + { WM_USER, sent|wparam|lparam, 0, 0 }, + { 0 } +}; +static const struct message end_dialog_2[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_USER, sent|wparam|lparam, 0, 0 }, + { 0 } +}; +static const struct message destroy_window[] = { + { HCBT_DESTROYWND, hook }, + { 0x0090, sent|optional }, + { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, + { WM_DESTROY, sent }, + { WM_NCDESTROY, sent }, + { 0 } +}; + +static LONG EndDialog_ret; + +static DWORD WINAPI EndDialog_thread(void *param) +{ + struct wnd_event *wnd_event = param; + + trace("thread: starting\n"); + WaitForSingleObject(wnd_event->start_event, INFINITE); + + /* make sure that GetMessage is called by main thread */ + Sleep(100); + + PostMessageA(wnd_event->hwnd, WM_USER, 0, 0); + + trace("thread: call EndDialog\n"); + EndDialog(wnd_event->hwnd, 0); + trace("thread: ret EndDialog\n"); + + InterlockedIncrement(&EndDialog_ret); + + return 0; +} + +static void test_EndDialog_other_thread(BOOL wait_send_message) +{ + DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT; + HANDLE hthread; + struct wnd_event wnd_event; + DWORD tid, ret; + MSG msg; + + EndDialog_ret = 0; + + wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL); + + wnd_event.hwnd = CreateDialogParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_dlg_proc, 0); + ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n"); + + hthread = CreateThread(NULL, 0, EndDialog_thread, &wnd_event, 0, &tid); + ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + + flush_events(); + flush_sequence(); + + ret = GetQueueStatus(QS_SENDMESSAGE); + ok(ret == 0, "wrong status %08x\n", ret); + + SetEvent(wnd_event.start_event); + + /* wait for other thread's SendMessage */ + if (wait_send_message) + { + for (;;) + { + ret = GetQueueStatus(QS_SENDMESSAGE); + if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break; + Sleep(50); + } + } + trace("main: call GetMessage\n"); + GetMessageA(&msg, 0, 0, 0); + ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message); + DispatchMessageA(&msg); + if (!wait_send_message) + ok_sequence(end_dialog_1, "EndDialog from other thread", FALSE); + else + ok_sequence(end_dialog_2, "EndDialog from other thread", FALSE); + + /* intentionally yield */ + MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input); + + trace("main: call DestroyWindow\n"); + DestroyWindow(wnd_event.hwnd); + trace("main: ret DestroyWindow\n"); + ok_sequence(destroy_window, "DestroyWindow", FALSE); + + ret = InterlockedIncrement(&EndDialog_ret); + if (!wait_send_message) + ok(EndDialog_ret == 1, "expected 1, got %u\n", ret); + else + ok(EndDialog_ret == 2, "expected 2, got %u\n", ret); + + trace("waiting for thread exit\n"); + WaitForSingleObject(hthread, INFINITE); + CloseHandle(hthread); + + ret = InterlockedIncrement(&EndDialog_ret); + ok(EndDialog_ret == 3, "expected 3, got %u\n", ret); + + flush_events(); + flush_sequence(); +} + static void init_funcs(void) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); @@ -14947,6 +15058,8 @@ START_TEST(msg) } hEvent_hook = 0; + test_EndDialog_other_thread(FALSE); + test_EndDialog_other_thread(TRUE); test_SendMessage_other_thread(1); test_SendMessage_other_thread(2); test_SetFocus(); -- 2.3.7