user32/tests: Add tests for message sequence of window destruction at thread exit.
This commit is contained in:
parent
95f8371a16
commit
d25f71b553
|
@ -885,7 +885,7 @@ static const struct message WmShowVisiblePopupSeq_3[] = {
|
||||||
{ EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
|
{ EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
|
||||||
{ WM_SETFOCUS, sent|defwinproc },
|
{ WM_SETFOCUS, sent|defwinproc },
|
||||||
{ WM_GETTEXT, sent|optional },
|
{ WM_GETTEXT, sent|optional },
|
||||||
{ WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
|
{ WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
/* CreateWindow (for child window, not initially visible) */
|
/* CreateWindow (for child window, not initially visible) */
|
||||||
|
@ -1125,6 +1125,13 @@ static const struct message WmDestroyChildSeq[] = {
|
||||||
{ WM_NCDESTROY, sent },
|
{ WM_NCDESTROY, sent },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
/* visible child window destroyed by thread exit */
|
||||||
|
static const struct message WmExitThreadSeq[] = {
|
||||||
|
{ WM_NCDESTROY, sent }, /* actually in grandchild */
|
||||||
|
{ WM_PAINT, sent|parent },
|
||||||
|
{ WM_ERASEBKGND, sent|parent|beginpaint },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
/* DestroyWindow for a visible child window with invisible parent */
|
/* DestroyWindow for a visible child window with invisible parent */
|
||||||
static const struct message WmDestroyInvisibleChildSeq[] = {
|
static const struct message WmDestroyInvisibleChildSeq[] = {
|
||||||
{ HCBT_DESTROYWND, hook },
|
{ HCBT_DESTROYWND, hook },
|
||||||
|
@ -6334,6 +6341,53 @@ static DWORD WINAPI thread_proc(void *param)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD CALLBACK create_grand_child_thread( void *param )
|
||||||
|
{
|
||||||
|
struct wnd_event *wnd_event = param;
|
||||||
|
HWND hchild;
|
||||||
|
MSG msg;
|
||||||
|
|
||||||
|
hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
|
||||||
|
WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
|
||||||
|
ok (hchild != 0, "Failed to create child window\n");
|
||||||
|
flush_events();
|
||||||
|
flush_sequence();
|
||||||
|
SetEvent( wnd_event->event );
|
||||||
|
|
||||||
|
while (GetMessage(&msg, 0, 0, 0))
|
||||||
|
{
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD CALLBACK create_child_thread( void *param )
|
||||||
|
{
|
||||||
|
struct wnd_event *wnd_event = param;
|
||||||
|
struct wnd_event child_event;
|
||||||
|
DWORD tid;
|
||||||
|
MSG msg;
|
||||||
|
|
||||||
|
child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
|
||||||
|
WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
|
||||||
|
ok (child_event.hwnd != 0, "Failed to create child window\n");
|
||||||
|
SetFocus( child_event.hwnd );
|
||||||
|
flush_events();
|
||||||
|
flush_sequence();
|
||||||
|
child_event.event = wnd_event->event;
|
||||||
|
CloseHandle( CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid) );
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
DWORD ret = MsgWaitForMultipleObjects(1, &child_event.event, FALSE, 1000, QS_SENDMESSAGE);
|
||||||
|
if (ret != 1) break;
|
||||||
|
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
Sleep( 200 ); /* leave parent the time to finish processing messages */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void test_interthread_messages(void)
|
static void test_interthread_messages(void)
|
||||||
{
|
{
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
|
@ -6401,6 +6455,30 @@ static void test_interthread_messages(void)
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
|
|
||||||
ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
|
ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
|
||||||
|
|
||||||
|
wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||||
|
100, 100, 200, 200, 0, 0, 0, NULL);
|
||||||
|
ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
|
||||||
|
flush_sequence();
|
||||||
|
log_all_parent_messages++;
|
||||||
|
wnd_event.event = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||||
|
hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ret = MsgWaitForMultipleObjects(1, &wnd_event.event, FALSE, 1000, QS_SENDMESSAGE);
|
||||||
|
if (ret != 1) break;
|
||||||
|
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
|
||||||
|
/* now wait for the thread without processing messages; this shouldn't deadlock */
|
||||||
|
ret = WaitForSingleObject( hThread, 5000 );
|
||||||
|
ok( !ret, "WaitForSingleObject failed %x\n", ret );
|
||||||
|
CloseHandle( hThread );
|
||||||
|
CloseHandle( wnd_event.event );
|
||||||
|
flush_events();
|
||||||
|
ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
|
||||||
|
log_all_parent_messages--;
|
||||||
|
DestroyWindow( wnd_event.hwnd );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue