diff --git a/rostests/winetests/user32/class.c b/rostests/winetests/user32/class.c index 1f689a38923..8f316aadabe 100755 --- a/rostests/winetests/user32/class.c +++ b/rostests/winetests/user32/class.c @@ -685,9 +685,16 @@ static void test_builtinproc(void) cls.lpfnWndProc = pDefWindowProcW; atom = RegisterClassExA(&cls); - hwnd = CreateWindowExW(0, classW, NULL, WS_OVERLAPPEDWINDOW, + hwnd = CreateWindowExW(0, classW, unistring, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleW(NULL), 0); - ok(IsWindowUnicode(hwnd), "Windows should be Unicode\n"); + ok(IsWindowUnicode(hwnd) || + broken(!IsWindowUnicode(hwnd)) /* Windows 8 and 10 */, + "Windows should be Unicode\n"); + SendMessageW(hwnd, WM_GETTEXT, sizeof(buf) / sizeof(buf[0]), (LPARAM)buf); + if (IsWindowUnicode(hwnd)) + ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); + else + ok(memcmp(buf, unistring, sizeof(unistring)) != 0, "WM_GETTEXT invalid return\n"); SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pDefWindowProcA); ok(IsWindowUnicode(hwnd), "Windows should have remained Unicode\n"); if (GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA) diff --git a/rostests/winetests/user32/clipboard.c b/rostests/winetests/user32/clipboard.c index 0b64c27a5eb..923f172601e 100755 --- a/rostests/winetests/user32/clipboard.c +++ b/rostests/winetests/user32/clipboard.c @@ -30,9 +30,8 @@ static BOOL (WINAPI *pAddClipboardFormatListener)(HWND hwnd); static BOOL (WINAPI *pRemoveClipboardFormatListener)(HWND hwnd); -static DWORD (WINAPI *pGetClipboardSequenceNumber)(void); +static BOOL (WINAPI *pGetUpdatedClipboardFormats)( UINT *formats, UINT count, UINT *out_count ); -static const BOOL is_win64 = sizeof(void *) > sizeof(int); static int thread_from_line; static char *argv0; @@ -107,7 +106,6 @@ static void set_clipboard_data_process( int arg ) SetLastError( 0xdeadbeef ); if (arg) { - todo_wine_if( arg == 1 || arg == 3 ) ok( IsClipboardFormatAvailable( CF_WAVE ), "process %u: CF_WAVE not available\n", arg ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); ok( ret != 0, "process %u: SetClipboardData failed err %u\n", arg, GetLastError() ); @@ -209,7 +207,7 @@ static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM { case WM_DESTROY: ok( wm_renderallformats, "didn't receive WM_RENDERALLFORMATS before WM_DESTROY\n" ); - todo_wine ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" ); + ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" ); break; case WM_DRAWCLIPBOARD: ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); @@ -323,7 +321,7 @@ static void test_ClipboardOwner(void) ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n"); ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n"); ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); - todo_wine ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" ); + ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" ); SetLastError( 0xdeadbeef ); ret = CloseClipboard(); @@ -418,12 +416,12 @@ todo_wine ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %d\n", GetLastError()); } - for (format_id = 0; format_id < 0xffff; format_id++) + for (format_id = 0; format_id < 0x10fff; format_id++) { SetLastError(0xdeadbeef); len = GetClipboardFormatNameA(format_id, buf, 256); - if (format_id < 0xc000) + if (format_id < 0xc000 || format_id > 0xffff) ok(!len, "GetClipboardFormatNameA should fail, but it returned %d (%s)\n", len, buf); else if (len && winetest_debug > 1) trace("%04x: %s\n", format_id, len ? buf : ""); @@ -485,19 +483,19 @@ todo_wine static HGLOBAL create_textA(void) { - HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5); + HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 10); char *p = GlobalLock(h); - strcpy(p, "test"); + memcpy(p, "test\0\0\0\0\0", 10); GlobalUnlock(h); return h; } static HGLOBAL create_textW(void) { - static const WCHAR testW[] = {'t','e','s','t',0}; - HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5 * sizeof(WCHAR)); + static const WCHAR testW[] = {'t','e','s','t',0,0,0,0,0,0}; + HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, sizeof(testW)); WCHAR *p = GlobalLock(h); - lstrcpyW(p, testW); + memcpy(p, testW, sizeof(testW)); GlobalUnlock(h); return h; } @@ -562,30 +560,51 @@ static HBITMAP create_dib( BOOL v5 ) return ret; } +static LRESULT CALLBACK renderer_winproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + static UINT rendered; + UINT ret; + + switch (msg) + { + case WM_RENDERFORMAT: + if (wp < 32) rendered |= (1 << wp); + break; + case WM_USER: + ret = rendered; + rendered = 0; + return ret; + } + return DefWindowProcA( hwnd, msg, wp, lp ); +} + static void test_synthesized(void) { static const struct test { UINT format; UINT expected[8]; - UINT todo; } tests[] = { -/* 0 */ { CF_TEXT, { CF_TEXT, CF_LOCALE, CF_OEMTEXT, CF_UNICODETEXT }, 1 << 1 }, - { CF_OEMTEXT, { CF_OEMTEXT, CF_LOCALE, CF_TEXT, CF_UNICODETEXT }, 1 << 1 }, - { CF_UNICODETEXT, { CF_UNICODETEXT, CF_LOCALE, CF_TEXT, CF_OEMTEXT }, 1 << 1 }, +/* 0 */ { CF_TEXT, { CF_TEXT, CF_LOCALE, CF_OEMTEXT, CF_UNICODETEXT }}, + { CF_OEMTEXT, { CF_OEMTEXT, CF_LOCALE, CF_TEXT, CF_UNICODETEXT }}, + { CF_UNICODETEXT, { CF_UNICODETEXT, CF_LOCALE, CF_TEXT, CF_OEMTEXT }}, { CF_ENHMETAFILE, { CF_ENHMETAFILE, CF_METAFILEPICT }}, { CF_METAFILEPICT, { CF_METAFILEPICT, CF_ENHMETAFILE }}, -/* 5 */ { CF_BITMAP, { CF_BITMAP, CF_DIB, CF_DIBV5 }, 1 << 2 }, - { CF_DIB, { CF_DIB, CF_BITMAP, CF_DIBV5 }, 1 << 2 }, - { CF_DIBV5, { CF_DIBV5, CF_BITMAP, CF_DIB }, (1 << 1) | (1 << 2) }, +/* 5 */ { CF_BITMAP, { CF_BITMAP, CF_DIB, CF_DIBV5 }}, + { CF_DIB, { CF_DIB, CF_BITMAP, CF_DIBV5 }}, + { CF_DIBV5, { CF_DIBV5, CF_BITMAP, CF_DIB }}, }; HGLOBAL h, htext; HENHMETAFILE emf; BOOL r; - UINT cf, i, j, count; + UINT cf, i, j, count, rendered, seq, old_seq; HANDLE data; + HWND hwnd; + + hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); + SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)renderer_winproc ); htext = create_textA(); emf = create_emf(); @@ -602,11 +621,11 @@ static void test_synthesized(void) ok(r, "gle %d\n", GetLastError()); count = CountClipboardFormats(); - todo_wine ok( count == 6, "count %u\n", count ); + ok( count == 6, "count %u\n", count ); r = IsClipboardFormatAvailable( CF_TEXT ); ok( r, "CF_TEXT not available err %d\n", GetLastError()); r = IsClipboardFormatAvailable( CF_LOCALE ); - todo_wine ok( r, "CF_LOCALE not available err %d\n", GetLastError()); + ok( r, "CF_LOCALE not available err %d\n", GetLastError()); r = IsClipboardFormatAvailable( CF_OEMTEXT ); ok( r, "CF_OEMTEXT not available err %d\n", GetLastError()); r = IsClipboardFormatAvailable( CF_UNICODETEXT ); @@ -629,13 +648,11 @@ static void test_synthesized(void) ok(data != NULL, "couldn't get data, cf %08x\n", cf); cf = EnumClipboardFormats(cf); - todo_wine ok(cf == CF_LOCALE, "cf %08x\n", cf); - if(cf == CF_LOCALE) - { - data = GetClipboardData(cf); - ok(data != NULL, "couldn't get data, cf %08x\n", cf); - cf = EnumClipboardFormats(cf); - } + ok(cf == CF_LOCALE, "cf %08x\n", cf); + data = GetClipboardData(cf); + ok(data != NULL, "couldn't get data, cf %08x\n", cf); + + cf = EnumClipboardFormats(cf); ok(cf == CF_OEMTEXT, "cf %08x\n", cf); data = GetClipboardData(cf); ok(data != NULL, "couldn't get data, cf %08x\n", cf); @@ -646,7 +663,7 @@ static void test_synthesized(void) cf = EnumClipboardFormats(cf); ok(cf == CF_METAFILEPICT, "cf %08x\n", cf); data = GetClipboardData(cf); - todo_wine ok(data != NULL, "couldn't get data, cf %08x\n", cf); + ok(data != NULL, "couldn't get data, cf %08x\n", cf); cf = EnumClipboardFormats(cf); ok(cf == 0, "cf %08x\n", cf); @@ -654,6 +671,42 @@ static void test_synthesized(void) r = EmptyClipboard(); ok(r, "gle %d\n", GetLastError()); + SetClipboardData( CF_UNICODETEXT, create_textW() ); + SetClipboardData( CF_TEXT, create_textA() ); + SetClipboardData( CF_OEMTEXT, create_textA() ); + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); + + r = OpenClipboard( NULL ); + ok(r, "gle %d\n", GetLastError()); + SetLastError( 0xdeadbeef ); + cf = EnumClipboardFormats(0); + ok( cf == CF_UNICODETEXT, "cf %08x\n", cf ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + cf = EnumClipboardFormats(cf); + ok( cf == CF_TEXT, "cf %08x\n", cf ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + cf = EnumClipboardFormats(cf); + ok( cf == CF_OEMTEXT, "cf %08x\n", cf ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + cf = EnumClipboardFormats(cf); + ok( cf == CF_LOCALE, "cf %08x\n", cf ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + cf = EnumClipboardFormats( cf ); + ok( cf == 0, "cf %08x\n", cf ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + cf = EnumClipboardFormats( 0xdead ); + ok( cf == 0, "cf %08x\n", cf ); + ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() ); + + r = EmptyClipboard(); + ok(r, "gle %d\n", GetLastError()); + r = CloseClipboard(); ok(r, "gle %d\n", GetLastError()); @@ -698,28 +751,29 @@ static void test_synthesized(void) for (j = 0; tests[i].expected[j]; j++) { r = IsClipboardFormatAvailable( tests[i].expected[j] ); - todo_wine_if (tests[i].todo & (1 << j)) ok( r, "%u: %04x not available\n", i, tests[i].expected[j] ); } - todo_wine_if (tests[i].todo) ok( count == j, "%u: count %u instead of %u\n", i, count, j ); - r = OpenClipboard(NULL); + r = OpenClipboard( hwnd ); ok(r, "%u: gle %d\n", i, GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) { cf = EnumClipboardFormats( cf ); - todo_wine_if (tests[i].todo & (1 << j)) ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n", i, j, cf, tests[i].expected[j] ); if (cf != tests[i].expected[j]) break; + old_seq = GetClipboardSequenceNumber(); data = GetClipboardData( cf ); - todo_wine_if (j && cf == CF_METAFILEPICT) ok(data != NULL || broken( tests[i].format == CF_DIBV5 && cf == CF_DIB ), /* >= Vista */ "%u: couldn't get data, cf %04x err %d\n", i, cf, GetLastError()); - if (cf == CF_LOCALE) + seq = GetClipboardSequenceNumber(); + ok(seq == old_seq, "sequence changed (test %d %d)\n", i, cf); + switch (cf) + { + case CF_LOCALE: { UINT *ptr = GlobalLock( data ); ok( GlobalSize( data ) == sizeof(*ptr), "%u: size %lu\n", i, GlobalSize( data )); @@ -727,6 +781,15 @@ static void test_synthesized(void) broken( *ptr == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )), "%u: CF_LOCALE %08x/%08x\n", i, *ptr, GetUserDefaultLCID() ); GlobalUnlock( data ); + break; + } + case CF_TEXT: + case CF_OEMTEXT: + ok( GlobalSize( data ) == 10, "wrong len %ld\n", GlobalSize( data )); + break; + case CF_UNICODETEXT: + ok( GlobalSize( data ) == 10 * sizeof(WCHAR), "wrong len %ld\n", GlobalSize( data )); + break; } } if (!tests[i].expected[j]) @@ -740,23 +803,30 @@ static void test_synthesized(void) r = EmptyClipboard(); ok(r, "%u: gle %d\n", i, GetLastError()); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + SetClipboardData( tests[i].format, 0 ); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); count = CountClipboardFormats(); ok( count == 1, "%u: count %u\n", i, count ); r = CloseClipboard(); ok(r, "%u: gle %d\n", i, GetLastError()); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); count = CountClipboardFormats(); for (j = 0; tests[i].expected[j]; j++) { r = IsClipboardFormatAvailable( tests[i].expected[j] ); - todo_wine_if (tests[i].todo & (1 << j)) ok( r, "%u: %04x not available\n", i, tests[i].expected[j] ); } - todo_wine_if (tests[i].todo) ok( count == j, "%u: count %u instead of %u\n", i, count, j ); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); r = OpenClipboard(NULL); ok(r, "%u: gle %d\n", i, GetLastError()); @@ -764,15 +834,29 @@ static void test_synthesized(void) for (j = 0; tests[i].expected[j]; j++) { cf = EnumClipboardFormats( cf ); - todo_wine_if (tests[i].todo & (1 << j)) ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n", i, j, cf, tests[i].expected[j] ); if (cf != tests[i].expected[j]) break; + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered ); data = GetClipboardData( cf ); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); if (cf == CF_LOCALE) + { ok(data != NULL, "%u: CF_LOCALE no data\n", i); + ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + } else + { ok(!data, "%u: format %04x got data %p\n", i, cf, data); + ok( rendered == (1 << tests[i].format), + "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + /* try to render a second time */ + data = GetClipboardData( cf ); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( rendered == (1 << tests[i].format), + "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + } } if (!tests[i].expected[j]) { @@ -781,6 +865,8 @@ static void test_synthesized(void) } r = CloseClipboard(); ok(r, "%u: gle %d\n", i, GetLastError()); + rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); + ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); } r = OpenClipboard(NULL); @@ -789,6 +875,14 @@ static void test_synthesized(void) ok(r, "gle %d\n", GetLastError()); r = CloseClipboard(); ok(r, "gle %d\n", GetLastError()); + DestroyWindow( hwnd ); +} + +static DWORD WINAPI clipboard_render_data_thread(void *param) +{ + HANDLE handle = SetClipboardData( CF_UNICODETEXT, create_textW() ); + ok( handle != 0, "SetClipboardData failed: %d\n", GetLastError() ); + return 0; } static CRITICAL_SECTION clipboard_cs; @@ -799,6 +893,7 @@ static UINT wm_destroyclipboard; static UINT wm_renderformat; static UINT nb_formats; static BOOL cross_thread; +static BOOL do_render_format; static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { @@ -831,6 +926,27 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA case WM_RENDERFORMAT: ok( !wm_renderformat, "multiple WM_RENDERFORMAT %04x / %04lx\n", wm_renderformat, wp ); wm_renderformat = wp; + + if (do_render_format) + { + UINT seq, old_seq; + HANDLE handle; + + old_seq = GetClipboardSequenceNumber(); + handle = SetClipboardData( CF_TEXT, create_textA() ); + ok( handle != 0, "SetClipboardData failed: %d\n", GetLastError() ); + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + old_seq = seq; + + handle = CreateThread( NULL, 0, clipboard_render_data_thread, NULL, 0, NULL ); + ok( handle != NULL, "CreateThread failed: %d\n", GetLastError() ); + ok( WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + CloseHandle( handle ); + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + } + break; case WM_CLIPBOARDUPDATE: ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %x\n", msg_flags ); @@ -865,6 +981,19 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA return DefWindowProcA(hwnd, msg, wp, lp); } +static void get_clipboard_data_process(void) +{ + HANDLE data; + BOOL r; + + r = OpenClipboard(0); + ok(r, "OpenClipboard failed: %d\n", GetLastError()); + data = GetClipboardData( CF_UNICODETEXT ); + ok( data != NULL, "GetClipboardData failed: %d\n", GetLastError()); + r = CloseClipboard(); + ok(r, "CloseClipboard failed: %d\n", GetLastError()); +} + static DWORD WINAPI clipboard_thread(void *param) { HWND ret, win = param; @@ -876,7 +1005,7 @@ static DWORD WINAPI clipboard_thread(void *param) cross_thread = (GetWindowThreadProcessId( win, NULL ) != GetCurrentThreadId()); trace( "%s-threaded test\n", cross_thread ? "multi" : "single" ); - if (pGetClipboardSequenceNumber) old_seq = pGetClipboardSequenceNumber(); + old_seq = GetClipboardSequenceNumber(); EnterCriticalSection(&clipboard_cs); SetLastError(0xdeadbeef); @@ -915,11 +1044,8 @@ static DWORD WINAPI clipboard_thread(void *param) ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError()); } - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( seq == old_seq, "sequence changed\n" ); - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); if (!cross_thread) { ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); @@ -942,11 +1068,8 @@ static DWORD WINAPI clipboard_thread(void *param) r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( seq == old_seq, "sequence changed\n" ); - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -964,12 +1087,9 @@ static DWORD WINAPI clipboard_thread(void *param) r = EmptyClipboard(); ok(r, "EmptyClipboard failed: %d\n", GetLastError()); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -989,12 +1109,9 @@ static DWORD WINAPI clipboard_thread(void *param) r = EmptyClipboard(); ok(r, "EmptyClipboard failed: %d\n", GetLastError()); /* sequence changes again, even though it was already empty */ - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1016,12 +1133,9 @@ static DWORD WINAPI clipboard_thread(void *param) handle = SetClipboardData( CF_TEXT, create_textA() ); ok(handle != 0, "SetClipboardData failed: %d\n", GetLastError()); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1038,12 +1152,9 @@ static DWORD WINAPI clipboard_thread(void *param) SetClipboardData( CF_UNICODETEXT, 0 ); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1060,12 +1171,9 @@ static DWORD WINAPI clipboard_thread(void *param) SetClipboardData( CF_UNICODETEXT, 0 ); /* same data again */ - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1089,12 +1197,9 @@ static DWORD WINAPI clipboard_thread(void *param) ok(r, "CloseClipboard failed: %d\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); @@ -1112,11 +1217,8 @@ static DWORD WINAPI clipboard_thread(void *param) r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( seq == old_seq, "sequence changed\n" ); - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1140,18 +1242,17 @@ static DWORD WINAPI clipboard_thread(void *param) fmt = SendMessageA( win, WM_USER+4, 0, 0 ); ok( fmt == CF_UNICODETEXT, "WM_RENDERFORMAT received %04x\n", fmt ); + do_render_format = TRUE; handle = GetClipboardData( CF_OEMTEXT ); - ok( !handle, "got data for CF_OEMTEXT\n" ); + ok( handle != NULL, "didn't get data for CF_OEMTEXT\n" ); fmt = SendMessageA( win, WM_USER+4, 0, 0 ); ok( fmt == CF_UNICODETEXT, "WM_RENDERFORMAT received %04x\n", fmt ); + do_render_format = FALSE; SetClipboardData( CF_WAVE, 0 ); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1168,13 +1269,10 @@ static DWORD WINAPI clipboard_thread(void *param) r = CloseClipboard(); ok(r, "CloseClipboard failed: %d\n", GetLastError()); - if (pGetClipboardSequenceNumber) - { - /* no synthesized format, so CloseClipboard doesn't change the sequence */ - seq = pGetClipboardSequenceNumber(); - todo_wine ok( seq == old_seq, "sequence changed\n" ); - old_seq = seq; - } + /* no synthesized format, so CloseClipboard doesn't change the sequence */ + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + old_seq = seq; if (!cross_thread) { ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); @@ -1194,11 +1292,8 @@ static DWORD WINAPI clipboard_thread(void *param) r = CloseClipboard(); ok(r, "CloseClipboard failed: %d\n", GetLastError()); /* nothing changed */ - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( seq == old_seq, "sequence changed\n" ); - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1244,12 +1339,9 @@ static DWORD WINAPI clipboard_thread(void *param) r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1271,12 +1363,9 @@ static DWORD WINAPI clipboard_thread(void *param) ok(r, "CloseClipboard failed: %d\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( seq == old_seq, "sequence changed\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + old_seq = seq; if (!cross_thread) { ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); @@ -1293,12 +1382,9 @@ static DWORD WINAPI clipboard_thread(void *param) run_process( "grab_clipboard 0" ); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1319,12 +1405,9 @@ static DWORD WINAPI clipboard_thread(void *param) r = OpenClipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1344,12 +1427,9 @@ static DWORD WINAPI clipboard_thread(void *param) ok(r, "CloseClipboard failed: %d\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( seq == old_seq, "sequence changed\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + old_seq = seq; if (!cross_thread) { ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD received\n" ); @@ -1366,12 +1446,9 @@ static DWORD WINAPI clipboard_thread(void *param) run_process( "grab_clipboard 1" ); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 2, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1392,12 +1469,9 @@ static DWORD WINAPI clipboard_thread(void *param) r = OpenClipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) == 1, "sequence diff %d\n", seq - old_seq ); + old_seq = seq; if (!cross_thread) { ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); @@ -1417,12 +1491,9 @@ static DWORD WINAPI clipboard_thread(void *param) ok(r, "CloseClipboard failed: %d\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); - if (pGetClipboardSequenceNumber) - { - seq = pGetClipboardSequenceNumber(); - todo_wine ok( seq == old_seq, "sequence changed\n" ); - old_seq = seq; - } + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + old_seq = seq; if (!cross_thread) { ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); @@ -1437,6 +1508,31 @@ static DWORD WINAPI clipboard_thread(void *param) fmt = SendMessageA( win, WM_USER+4, 0, 0 ); ok( !fmt, "WM_RENDERFORMAT received\n" ); + if (cross_thread) + { + r = OpenClipboard( win ); + ok(r, "OpenClipboard failed: %d\n", GetLastError()); + r = EmptyClipboard(); + ok(r, "EmptyClipboard failed: %d\n", GetLastError()); + SetClipboardData( CF_TEXT, 0 ); + r = CloseClipboard(); + ok(r, "CloseClipboard failed: %d\n", GetLastError()); + + do_render_format = TRUE; + old_seq = GetClipboardSequenceNumber(); + run_process( "get_clipboard_data" ); + seq = GetClipboardSequenceNumber(); + ok( seq == old_seq, "sequence changed\n" ); + do_render_format = FALSE; + + count = SendMessageA( win, WM_USER+1, 0, 0 ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); + count = SendMessageA( win, WM_USER+2, 0, 0 ); + ok( count == 1 || broken(!pAddClipboardFormatListener) /* < Vista */, "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( fmt == CF_TEXT, "WM_RENDERFORMAT received\n" ); + } + r = PostMessageA(win, WM_USER, 0, 0); ok(r, "PostMessage failed: %d\n", GetLastError()); @@ -1518,32 +1614,51 @@ static BOOL is_fixed( HANDLE handle ) static BOOL is_freed( HANDLE handle ) { - void *ptr = GlobalLock( handle ); - if (ptr) GlobalUnlock( handle ); - return !ptr; + return !GlobalSize( handle ); } static UINT format_id; static HBITMAP bitmap, bitmap2; static HPALETTE palette; -static HPEN pen; -static const LOGPALETTE logpalette = { 0x300, 1 }; +static const LOGPALETTE logpalette = { 0x300, 1, {{ 0x12, 0x34, 0x56, 0x78 }}}; static void test_handles( HWND hwnd ) { - HGLOBAL h, htext, htext2; + HGLOBAL h, htext, htext2, htext3, htext4, htext5; + HGLOBAL hfixed, hfixed2, hmoveable, empty_fixed, empty_moveable; + void *ptr; + UINT format_id2 = RegisterClipboardFormatA( "another format" ); BOOL r; HANDLE data; + HBITMAP bitmap_temp; DWORD process; BOOL is_owner = (GetWindowThreadProcessId( hwnd, &process ) && process == GetCurrentProcessId()); trace( "hwnd %p\n", hwnd ); htext = create_textA(); htext2 = create_textA(); + htext3 = create_textA(); + htext4 = create_textA(); + htext5 = create_textA(); bitmap = CreateBitmap( 10, 10, 1, 1, NULL ); bitmap2 = CreateBitmap( 10, 10, 1, 1, NULL ); palette = CreatePalette( &logpalette ); - pen = CreatePen( PS_SOLID, 1, 0 ); + + hfixed = GlobalAlloc( GMEM_FIXED, 17 ); + hfixed2 = GlobalAlloc( GMEM_FIXED, 17 ); + ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed ); + ok( GlobalSize( hfixed ) == 17, "wrong size %lu\n", GlobalSize( hfixed )); + + hmoveable = GlobalAlloc( GMEM_MOVEABLE, 23 ); + ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable ); + ok( GlobalSize( hmoveable ) == 23, "wrong size %lu\n", GlobalSize( hmoveable )); + + empty_fixed = GlobalAlloc( GMEM_FIXED, 0 ); + ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); + + empty_moveable = GlobalAlloc( GMEM_MOVEABLE, 0 ); + /* discarded handles can't be GlobalLock'ed */ + ok( is_freed( empty_moveable ), "expected free mem %p\n", empty_moveable ); r = OpenClipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); @@ -1556,21 +1671,55 @@ static void test_handles( HWND hwnd ) h = SetClipboardData( format_id, htext2 ); ok( h == htext2, "got %p\n", h ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); + bitmap_temp = CreateBitmap( 10, 10, 1, 1, NULL ); + h = SetClipboardData( CF_BITMAP, bitmap_temp ); + ok( h == bitmap_temp, "got %p\n", h ); + ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); h = SetClipboardData( CF_BITMAP, bitmap ); ok( h == bitmap, "got %p\n", h ); ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + ok( !GetObjectType( bitmap_temp ), "expected free object %p\n", bitmap_temp ); + h = SetClipboardData( CF_DSPBITMAP, bitmap2 ); + ok( h == bitmap2, "got %p\n", h ); + ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); h = SetClipboardData( CF_PALETTE, palette ); ok( h == palette, "got %p\n", h ); ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h ); - /* setting custom GDI formats crashes on 64-bit Windows */ - if (!is_win64) + h = SetClipboardData( CF_GDIOBJFIRST + 3, htext3 ); + ok( h == htext3, "got %p\n", h ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = SetClipboardData( CF_PRIVATEFIRST + 7, htext5 ); + ok( h == htext5, "got %p\n", h ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = SetClipboardData( format_id2, empty_moveable ); + ok( !h, "got %p\n", h ); + GlobalFree( empty_moveable ); + + if (0) /* crashes on vista64 */ { - h = SetClipboardData( CF_GDIOBJFIRST + 1, bitmap2 ); - ok( h == bitmap2, "got %p\n", h ); - ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); - h = SetClipboardData( CF_GDIOBJFIRST + 2, pen ); - ok( h == pen, "got %p\n", h ); - ok( GetObjectType( h ) == OBJ_PEN, "expected pen %p\n", h ); + ptr = HeapAlloc( GetProcessHeap(), 0, 0 ); + h = SetClipboardData( format_id2, ptr ); + ok( !h, "got %p\n", h ); + HeapFree( GetProcessHeap(), 0, ptr ); + } + + h = SetClipboardData( format_id2, empty_fixed ); + ok( h == empty_fixed, "got %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + h = SetClipboardData( 0xdeadbeef, hfixed2 ); + ok( h == hfixed2, "got %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + h = SetClipboardData( 0xdeadbabe, hmoveable ); + ok( h == hmoveable, "got %p\n", h ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + + ptr = HeapAlloc( GetProcessHeap(), 0, 37 ); + h = SetClipboardData( 0xdeadfade, ptr ); + ok( h == ptr || !h, "got %p\n", h ); + if (!h) /* heap blocks are rejected on >= win8 */ + { + HeapFree( GetProcessHeap(), 0, ptr ); + ptr = NULL; } data = GetClipboardData( CF_TEXT ); @@ -1581,16 +1730,56 @@ static void test_handles( HWND hwnd ) ok( data == htext2, "wrong data %p, cf %08x\n", data, format_id ); ok( is_moveable( data ), "expected moveable mem %p\n", data ); + data = GetClipboardData( CF_GDIOBJFIRST + 3 ); + ok( data == htext3, "wrong data %p\n", data ); + ok( is_moveable( data ), "expected moveable mem %p\n", data ); + + data = GetClipboardData( CF_PRIVATEFIRST + 7 ); + ok( data == htext5, "wrong data %p\n", data ); + ok( is_moveable( data ), "expected moveable mem %p\n", data ); + + data = GetClipboardData( format_id2 ); + ok( data == empty_fixed, "wrong data %p\n", data ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + + data = GetClipboardData( 0xdeadbeef ); + ok( data == hfixed2, "wrong data %p\n", data ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + + data = GetClipboardData( 0xdeadbabe ); + ok( data == hmoveable, "wrong data %p\n", data ); + ok( is_moveable( data ), "expected moveable mem %p\n", data ); + + data = GetClipboardData( 0xdeadfade ); + ok( data == ptr, "wrong data %p\n", data ); + + h = SetClipboardData( CF_PRIVATEFIRST + 7, htext4 ); + ok( h == htext4, "got %p\n", h ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + ok( is_freed( htext5 ), "expected freed mem %p\n", htext5 ); + + h = SetClipboardData( 0xdeadbeef, hfixed ); + ok( h == hfixed, "got %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); +#ifndef _WIN64 + /* testing if hfixed2 is freed triggers an exception on Win64 */ + ok( is_freed( hfixed2 ) || broken( !is_freed( hfixed2 )) /* < Vista */, "expected freed mem %p\n", hfixed2 ); +#endif + r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); /* data handles are still valid */ ok( is_moveable( htext ), "expected moveable mem %p\n", htext ); - ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext ); + ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext2 ); + ok( is_moveable( htext3 ), "expected moveable mem %p\n", htext3 ); + ok( is_moveable( htext4 ), "expected moveable mem %p\n", htext4 ); ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap ); ok( GetObjectType( bitmap2 ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap2 ); ok( GetObjectType( palette ) == OBJ_PAL, "expected palette %p\n", palette ); - ok( GetObjectType( pen ) == OBJ_PEN, "expected pen %p\n", pen ); + ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed ); + ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable ); + ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); r = OpenClipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); @@ -1598,62 +1787,110 @@ static void test_handles( HWND hwnd ) /* and now they are freed, unless we are the owner */ if (!is_owner) { - todo_wine ok( is_freed( htext ), "expected freed mem %p\n", htext ); - todo_wine ok( is_freed( htext2 ), "expected freed mem %p\n", htext ); + ok( is_freed( htext ), "expected freed mem %p\n", htext ); + ok( is_freed( htext2 ), "expected freed mem %p\n", htext2 ); + ok( is_freed( htext3 ), "expected freed mem %p\n", htext3 ); + ok( is_freed( htext4 ), "expected freed mem %p\n", htext4 ); + ok( is_freed( hmoveable ), "expected freed mem %p\n", hmoveable ); data = GetClipboardData( CF_TEXT ); - todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); data = GetClipboardData( format_id ); - todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + + data = GetClipboardData( CF_GDIOBJFIRST + 3 ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + + data = GetClipboardData( CF_PRIVATEFIRST + 7 ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + + data = GetClipboardData( format_id2 ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + ok( GlobalSize( data ) == 1, "wrong size %lu\n", GlobalSize( data )); + + data = GetClipboardData( 0xdeadbeef ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + ok( GlobalSize( data ) == 17, "wrong size %lu\n", GlobalSize( data )); + + data = GetClipboardData( 0xdeadbabe ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); + ok( GlobalSize( data ) == 23, "wrong size %lu\n", GlobalSize( data )); + + data = GetClipboardData( 0xdeadfade ); + ok( is_fixed( data ) || !ptr, "expected fixed mem %p\n", data ); + if (ptr) ok( GlobalSize( data ) == 37, "wrong size %lu\n", GlobalSize( data )); } else { ok( is_moveable( htext ), "expected moveable mem %p\n", htext ); - ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext ); + ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext2 ); + ok( is_moveable( htext3 ), "expected moveable mem %p\n", htext3 ); + ok( is_moveable( htext4 ), "expected moveable mem %p\n", htext4 ); + ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable ); data = GetClipboardData( CF_TEXT ); ok( data == htext, "wrong data %p\n", data ); data = GetClipboardData( format_id ); ok( data == htext2, "wrong data %p, cf %08x\n", data, format_id ); + + data = GetClipboardData( CF_GDIOBJFIRST + 3 ); + ok( data == htext3, "wrong data %p\n", data ); + + data = GetClipboardData( CF_PRIVATEFIRST + 7 ); + ok( data == htext4, "wrong data %p\n", data ); + + data = GetClipboardData( format_id2 ); + ok( data == empty_fixed, "wrong data %p\n", data ); + + data = GetClipboardData( 0xdeadbeef ); + ok( data == hfixed, "wrong data %p\n", data ); + + data = GetClipboardData( 0xdeadbabe ); + ok( data == hmoveable, "wrong data %p\n", data ); + + data = GetClipboardData( 0xdeadfade ); + ok( data == ptr, "wrong data %p\n", data ); } data = GetClipboardData( CF_OEMTEXT ); ok( is_fixed( data ), "expected fixed mem %p\n", data ); data = GetClipboardData( CF_UNICODETEXT ); ok( is_fixed( data ), "expected fixed mem %p\n", data ); + data = GetClipboardData( CF_LOCALE ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); data = GetClipboardData( CF_BITMAP ); ok( data == bitmap, "expected bitmap %p\n", data ); + data = GetClipboardData( CF_DSPBITMAP ); + ok( data == bitmap2, "expected bitmap %p\n", data ); data = GetClipboardData( CF_PALETTE ); ok( data == palette, "expected palette %p\n", data ); - if (!is_win64) - { - data = GetClipboardData( CF_GDIOBJFIRST + 1 ); - ok( data == bitmap2, "expected bitmap2 %p\n", data ); - data = GetClipboardData( CF_GDIOBJFIRST + 2 ); - ok( data == pen, "expected pen %p\n", data ); - } data = GetClipboardData( CF_DIB ); ok( is_fixed( data ), "expected fixed mem %p\n", data ); data = GetClipboardData( CF_DIBV5 ); - todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data ); + ok( is_fixed( data ), "expected fixed mem %p\n", data ); ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap ); ok( GetObjectType( bitmap2 ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap2 ); ok( GetObjectType( palette ) == OBJ_PAL, "expected palette %p\n", palette ); - ok( GetObjectType( pen ) == OBJ_PEN, "expected pen %p\n", pen ); + ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed ); + ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); /* w2003, w2008 don't seem to free the data here */ ok( is_freed( htext ) || broken( !is_freed( htext )), "expected freed mem %p\n", htext ); - ok( is_freed( htext2 ) || broken( !is_freed( htext2 )), "expected freed mem %p\n", htext ); + ok( is_freed( htext2 ) || broken( !is_freed( htext2 )), "expected freed mem %p\n", htext2 ); + ok( is_freed( htext3 ) || broken( !is_freed( htext3 )), "expected freed mem %p\n", htext3 ); + ok( is_freed( htext4 ) || broken( !is_freed( htext4 )), "expected freed mem %p\n", htext4 ); + ok( is_freed( hmoveable ) || broken( !is_freed( hmoveable )), "expected freed mem %p\n", hmoveable ); + ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed ); + ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed ); ok( !GetObjectType( bitmap ), "expected freed handle %p\n", bitmap ); + ok( !GetObjectType( bitmap2 ), "expected freed handle %p\n", bitmap2 ); ok( !GetObjectType( palette ), "expected freed handle %p\n", palette ); - ok( GetObjectType( bitmap2 ) == OBJ_BITMAP, "expected bitmap2 %p\n", bitmap2 ); - ok( GetObjectType( pen ) == OBJ_PEN, "expected pen %p\n", pen ); r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -1684,29 +1921,34 @@ static DWORD WINAPI test_handles_thread2( void *arg ) ptr = GlobalLock( h ); if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr ); GlobalUnlock( h ); + h = GetClipboardData( CF_GDIOBJFIRST + 3 ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + ptr = GlobalLock( h ); + if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr ); + GlobalUnlock( h ); + trace( "gdiobj %p\n", h ); + h = GetClipboardData( CF_PRIVATEFIRST + 7 ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + ptr = GlobalLock( h ); + if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr ); + GlobalUnlock( h ); + trace( "private %p\n", h ); h = GetClipboardData( CF_BITMAP ); ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); ok( h == bitmap, "different bitmap %p / %p\n", h, bitmap ); trace( "bitmap %p\n", h ); + h = GetClipboardData( CF_DSPBITMAP ); + ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + ok( h == bitmap2, "different bitmap %p / %p\n", h, bitmap2 ); + trace( "bitmap2 %p\n", h ); h = GetClipboardData( CF_PALETTE ); ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h ); ok( h == palette, "different palette %p / %p\n", h, palette ); trace( "palette %p\n", h ); - if (!is_win64) - { - h = GetClipboardData( CF_GDIOBJFIRST + 1 ); - ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); - ok( h == bitmap2, "different bitmap %p / %p\n", h, bitmap2 ); - trace( "bitmap2 %p\n", h ); - h = GetClipboardData( CF_GDIOBJFIRST + 2 ); - ok( GetObjectType( h ) == OBJ_PEN, "expected pen %p\n", h ); - ok( h == pen, "different pen %p / %p\n", h, pen ); - trace( "pen %p\n", h ); - } h = GetClipboardData( CF_DIB ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); h = GetClipboardData( CF_DIBV5 ); - todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); return 0; @@ -1717,36 +1959,105 @@ static void test_handles_process( const char *str ) BOOL r; HANDLE h; char *ptr; + BITMAP bm; + PALETTEENTRY entry; + BYTE buffer[1024]; format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" ); r = OpenClipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); - todo_wine_if( !h ) ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); ptr = GlobalLock( h ); - if (ptr) todo_wine ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr ); + ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr ); GlobalUnlock( h ); h = GetClipboardData( format_id ); - todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); ptr = GlobalLock( h ); if (ptr) ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr ); GlobalUnlock( h ); + h = GetClipboardData( CF_GDIOBJFIRST + 3 ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ptr = GlobalLock( h ); + ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr ); + GlobalUnlock( h ); + trace( "gdiobj %p\n", h ); + h = GetClipboardData( CF_PRIVATEFIRST + 7 ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ptr = GlobalLock( h ); + ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr ); + GlobalUnlock( h ); + trace( "private %p\n", h ); h = GetClipboardData( CF_BITMAP ); - todo_wine ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + ok( GetObjectW( h, sizeof(bm), &bm ) == sizeof(bm), "GetObject %p failed\n", h ); + ok( bm.bmWidth == 13 && bm.bmHeight == 17, "wrong bitmap %ux%u\n", bm.bmWidth, bm.bmHeight ); trace( "bitmap %p\n", h ); - h = GetClipboardData( CF_PALETTE ); - todo_wine ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h ); - trace( "palette %p\n", h ); - h = GetClipboardData( CF_GDIOBJFIRST + 1 ); - ok( !GetObjectType( h ), "expected invalid %p\n", h ); + h = GetClipboardData( CF_DSPBITMAP ); + ok( !GetObjectType( h ), "expected invalid object %p\n", h ); trace( "bitmap2 %p\n", h ); - h = GetClipboardData( CF_GDIOBJFIRST + 2 ); - ok( !GetObjectType( h ), "expected invalid %p\n", h ); - trace( "pen %p\n", h ); + h = GetClipboardData( CF_PALETTE ); + ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h ); + ok( GetPaletteEntries( h, 0, 1, &entry ) == 1, "GetPaletteEntries %p failed\n", h ); + ok( entry.peRed == 0x12 && entry.peGreen == 0x34 && entry.peBlue == 0x56, + "wrong color %02x,%02x,%02x\n", entry.peRed, entry.peGreen, entry.peBlue ); + trace( "palette %p\n", h ); + h = GetClipboardData( CF_METAFILEPICT ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE, + "wrong object %p\n", ((METAFILEPICT *)h)->hMF ); + trace( "metafile %p\n", h ); + h = GetClipboardData( CF_DSPMETAFILEPICT ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE, + "wrong object %p\n", ((METAFILEPICT *)h)->hMF ); + trace( "metafile2 %p\n", h ); + h = GetClipboardData( CF_ENHMETAFILE ); + ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h ); + ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER), + "GetEnhMetaFileBits failed on %p\n", h ); + ok( ((ENHMETAHEADER *)buffer)->nRecords == 3, + "wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords ); + trace( "enhmetafile %p\n", h ); + h = GetClipboardData( CF_DSPENHMETAFILE ); + ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h ); + ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER), + "GetEnhMetaFileBits failed on %p\n", h ); + ok( ((ENHMETAHEADER *)buffer)->nRecords == 3, + "wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords ); + trace( "enhmetafile2 %p\n", h ); h = GetClipboardData( CF_DIB ); - todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); h = GetClipboardData( CF_DIBV5 ); - todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); +} + +static void test_handles_process_open( const char *str ) +{ + HANDLE h, text = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, strlen(str) + 1 ); + char *ptr = GlobalLock( text ); + + strcpy( ptr, str ); + GlobalUnlock( text ); + + /* clipboard already open by parent process */ + h = SetClipboardData( CF_TEXT, text ); + ok( h == text, "wrong mem %p / %p\n", h, text ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); +} + +static void test_handles_process_dib( const char *str ) +{ + BOOL r; + HANDLE h; + + r = OpenClipboard( 0 ); + ok( r, "gle %d\n", GetLastError() ); + h = GetClipboardData( CF_BITMAP ); + ok( !GetObjectType( h ), "expected invalid object %p\n", h ); + trace( "dibsection %p\n", h ); r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); } @@ -1754,8 +2065,11 @@ static void test_handles_process( const char *str ) static void test_data_handles(void) { BOOL r; - HANDLE h; + char *ptr; + HANDLE h, text; HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); + BITMAPINFO bmi; + void *bits; ok( hwnd != 0, "window creation failed\n" ); format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" ); @@ -1764,10 +2078,9 @@ static void test_data_handles(void) test_handles( hwnd ); run_thread( test_handles_thread, hwnd, __LINE__ ); - bitmap = CreateBitmap( 10, 10, 1, 1, NULL ); + bitmap = CreateBitmap( 13, 17, 1, 1, NULL ); bitmap2 = CreateBitmap( 10, 10, 1, 1, NULL ); palette = CreatePalette( &logpalette ); - pen = CreatePen( PS_SOLID, 1, 0 ); r = OpenClipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); @@ -1779,15 +2092,26 @@ static void test_data_handles(void) ok( is_moveable( h ), "expected moveable mem %p\n", h ); h = SetClipboardData( CF_BITMAP, bitmap ); ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + h = SetClipboardData( CF_DSPBITMAP, bitmap2 ); + ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); h = SetClipboardData( CF_PALETTE, palette ); ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h ); - if (!is_win64) - { - h = SetClipboardData( CF_GDIOBJFIRST + 1, bitmap2 ); - ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); - h = SetClipboardData( CF_GDIOBJFIRST + 2, pen ); - ok( GetObjectType( h ) == OBJ_PEN, "expected pen %p\n", h ); - } + h = SetClipboardData( CF_METAFILEPICT, create_metafile() ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + trace( "metafile %p\n", h ); + h = SetClipboardData( CF_DSPMETAFILEPICT, create_metafile() ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + trace( "metafile2 %p\n", h ); + h = SetClipboardData( CF_ENHMETAFILE, create_emf() ); + ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h ); + trace( "enhmetafile %p\n", h ); + h = SetClipboardData( CF_DSPENHMETAFILE, create_emf() ); + ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h ); + trace( "enhmetafile2 %p\n", h ); + h = SetClipboardData( CF_GDIOBJFIRST + 3, create_textA() ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = SetClipboardData( CF_PRIVATEFIRST + 7, create_textA() ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -1800,14 +2124,302 @@ static void test_data_handles(void) ok( is_moveable( h ), "expected moveable mem %p\n", h ); h = GetClipboardData( format_id ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = GetClipboardData( CF_GDIOBJFIRST + 3 ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = GetClipboardData( CF_PRIVATEFIRST + 7 ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); + text = create_textA(); + h = SetClipboardData( CF_TEXT, text ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + + run_process( "handles_open foobar" ); + + ok( is_moveable( text ), "expected moveable mem %p\n", text ); + h = GetClipboardData( CF_TEXT ); + ok( is_fixed( h ), "expected fixed mem %p\n", h ); + ok( is_moveable( text ), "expected moveable mem %p\n", text ); + ptr = GlobalLock( h ); + ok( !strcmp( ptr, "foobar" ), "wrong data '%.8s'\n", ptr ); + GlobalUnlock( h ); + + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + ok( is_fixed( h ), "expected free mem %p\n", h ); + ok( is_freed( text ) || broken( is_moveable(text) ), /* w2003, w2008 */ + "expected free mem %p\n", text ); + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + /* test CF_BITMAP with a DIB section */ + memset( &bmi, 0, sizeof(bmi) ); + bmi.bmiHeader.biSize = sizeof( bmi.bmiHeader ); + bmi.bmiHeader.biWidth = 29; + bmi.bmiHeader.biHeight = 13; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bitmap = CreateDIBSection( 0, &bmi, DIB_RGB_COLORS, &bits, 0, 0 ); + + r = OpenClipboard( hwnd ); + ok( r, "gle %d\n", GetLastError() ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + h = SetClipboardData( CF_BITMAP, bitmap ); + ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + trace( "dibsection %p\n", h ); + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + run_process( "handles_dib dummy" ); + + r = OpenClipboard( hwnd ); + ok( r, "gle %d\n", GetLastError() ); + ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + ok( !GetObjectType( bitmap ), "expected deleted %p\n", bitmap ); r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); DestroyWindow( hwnd ); } +static void test_GetUpdatedClipboardFormats(void) +{ + BOOL r; + UINT count, formats[256]; + + if (!pGetUpdatedClipboardFormats) + { + win_skip( "GetUpdatedClipboardFormats not supported\n" ); + return; + } + + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( NULL, 0, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( !count, "wrong count %u\n", count ); + + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( NULL, 256, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( !count, "wrong count %u\n", count ); + + SetLastError( 0xdeadbeef ); + r = pGetUpdatedClipboardFormats( formats, 256, NULL ); + ok( !r, "succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( formats, 256, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( !count, "wrong count %u\n", count ); + + r = OpenClipboard( 0 ); + ok( r, "gle %d\n", GetLastError() ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( formats, 256, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( !count, "wrong count %u\n", count ); + + SetClipboardData( CF_UNICODETEXT, 0 ); + + count = 0xdeadbeef; + memset( formats, 0xcc, sizeof(formats) ); + r = pGetUpdatedClipboardFormats( formats, 256, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( count == 1, "wrong count %u\n", count ); + ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] ); + ok( formats[1] == 0xcccccccc, "wrong format %u\n", formats[1] ); + + SetClipboardData( CF_TEXT, 0 ); + count = 0xdeadbeef; + memset( formats, 0xcc, sizeof(formats) ); + r = pGetUpdatedClipboardFormats( formats, 256, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( count == 2, "wrong count %u\n", count ); + ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] ); + ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] ); + ok( formats[2] == 0xcccccccc, "wrong format %u\n", formats[2] ); + + SetLastError( 0xdeadbeef ); + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( formats, 0, &count ); + ok( !r, "succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() ); + ok( count == 2, "wrong count %u\n", count ); + + SetLastError( 0xdeadbeef ); + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( formats, 1, &count ); + ok( !r, "succeeded\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() ); + ok( count == 2, "wrong count %u\n", count ); + + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + count = 0xdeadbeef; + memset( formats, 0xcc, sizeof(formats) ); + r = pGetUpdatedClipboardFormats( formats, 256, &count ); + ok( r, "gle %d\n", GetLastError() ); + ok( count == 4, "wrong count %u\n", count ); + ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] ); + ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] ); + ok( formats[2] == CF_LOCALE, "wrong format %u\n", formats[2] ); + ok( formats[3] == CF_OEMTEXT, "wrong format %u\n", formats[3] ); + ok( formats[4] == 0xcccccccc, "wrong format %u\n", formats[4] ); + + count = 0xdeadbeef; + memset( formats, 0xcc, sizeof(formats) ); + r = pGetUpdatedClipboardFormats( formats, 2, &count ); + ok( !r, "gle %d\n", GetLastError() ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() ); + ok( count == 4, "wrong count %u\n", count ); + ok( formats[0] == 0xcccccccc, "wrong format %u\n", formats[0] ); + + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( NULL, 256, &count ); + ok( !r, "gle %d\n", GetLastError() ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( count == 4, "wrong count %u\n", count ); + + count = 0xdeadbeef; + r = pGetUpdatedClipboardFormats( NULL, 256, &count ); + ok( !r, "gle %d\n", GetLastError() ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( count == 4, "wrong count %u\n", count ); +} + +static const struct +{ + char strA[12]; + WCHAR strW[12]; + UINT len; +} test_data[] = +{ + { "foo", {0}, 3 }, /* 0 */ + { "foo", {0}, 4 }, + { "foo\0bar", {0}, 7 }, + { "foo\0bar", {0}, 8 }, + { "", {'f','o','o'}, 3 * sizeof(WCHAR) }, + { "", {'f','o','o',0}, 4 * sizeof(WCHAR) }, /* 5 */ + { "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) }, + { "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) }, + { "", {'f','o','o'}, 1 }, + { "", {'f','o','o'}, 2 }, + { "", {'f','o','o'}, 5 }, /* 10 */ + { "", {'f','o','o',0}, 7 }, + { "", {'f','o','o',0}, 9 }, +}; + +static void test_string_data(void) +{ + UINT i; + BOOL r; + HANDLE data; + char cmd[16]; + char bufferA[12]; + WCHAR bufferW[12]; + + for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) + { + /* 1-byte Unicode strings crash on Win64 */ +#ifdef _WIN64 + if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue; +#endif + r = OpenClipboard( 0 ); + ok( r, "gle %d\n", GetLastError() ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + data = GlobalAlloc( GMEM_FIXED, test_data[i].len ); + if (test_data[i].strA[0]) + { + memcpy( data, test_data[i].strA, test_data[i].len ); + SetClipboardData( CF_TEXT, data ); + memcpy( bufferA, test_data[i].strA, test_data[i].len ); + bufferA[test_data[i].len - 1] = 0; + ok( !memcmp( data, bufferA, test_data[i].len ), + "%u: wrong data %.*s\n", i, test_data[i].len, (char *)data ); + } + else + { + memcpy( data, test_data[i].strW, test_data[i].len ); + SetClipboardData( CF_UNICODETEXT, data ); + memcpy( bufferW, test_data[i].strW, test_data[i].len ); + bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; + ok( !memcmp( data, bufferW, test_data[i].len ), + "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) )); + } + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + sprintf( cmd, "string_data %u", i ); + run_process( cmd ); + } +} + +static void test_string_data_process( int i ) +{ + BOOL r; + HANDLE data; + UINT len, len2; + char bufferA[12]; + WCHAR bufferW[12]; + + r = OpenClipboard( 0 ); + ok( r, "gle %d\n", GetLastError() ); + if (test_data[i].strA[0]) + { + data = GetClipboardData( CF_TEXT ); + ok( data != 0, "%u: could not get data\n", i ); + len = GlobalSize( data ); + ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len ); + memcpy( bufferA, test_data[i].strA, test_data[i].len ); + bufferA[test_data[i].len - 1] = 0; + ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data ); + data = GetClipboardData( CF_UNICODETEXT ); + ok( data != 0, "%u: could not get data\n", i ); + len = GlobalSize( data ); + len2 = MultiByteToWideChar( CP_ACP, 0, bufferA, test_data[i].len, bufferW, 12 ); + ok( len == len2 * sizeof(WCHAR), "%u: wrong size %u / %u\n", i, len, len2 ); + ok( !memcmp( data, bufferW, len ), "%u: wrong data %s\n", i, wine_dbgstr_wn( data, len2 )); + } + else + { + data = GetClipboardData( CF_UNICODETEXT ); + ok( data != 0, "%u: could not get data\n", i ); + len = GlobalSize( data ); + ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len ); + memcpy( bufferW, test_data[i].strW, test_data[i].len ); + bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; + ok( !memcmp( data, bufferW, len ), + "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) )); + data = GetClipboardData( CF_TEXT ); + if (test_data[i].len >= sizeof(WCHAR)) + { + ok( data != 0, "%u: could not get data\n", i ); + len = GlobalSize( data ); + len2 = WideCharToMultiByte( CP_ACP, 0, bufferW, test_data[i].len / sizeof(WCHAR), + bufferA, 12, NULL, NULL ); + bufferA[len2 - 1] = 0; + ok( len == len2, "%u: wrong size %u / %u\n", i, len, len2 ); + ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data ); + } + else + { + ok( !data, "%u: got data for empty string\n", i ); + ok( IsClipboardFormatAvailable( CF_TEXT ), "%u: text not available\n", i ); + } + } + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); +} + START_TEST(clipboard) { char **argv; @@ -1817,7 +2429,7 @@ START_TEST(clipboard) argv0 = argv[0]; pAddClipboardFormatListener = (void *)GetProcAddress( mod, "AddClipboardFormatListener" ); pRemoveClipboardFormatListener = (void *)GetProcAddress( mod, "RemoveClipboardFormatListener" ); - pGetClipboardSequenceNumber = (void *)GetProcAddress( mod, "GetClipboardSequenceNumber" ); + pGetUpdatedClipboardFormats = (void *)GetProcAddress( mod, "GetUpdatedClipboardFormats" ); if (argc == 4 && !strcmp( argv[2], "set_clipboard_data" )) { @@ -1834,10 +2446,32 @@ START_TEST(clipboard) test_handles_process( argv[3] ); return; } + if (argc == 4 && !strcmp( argv[2], "handles_open" )) + { + test_handles_process_open( argv[3] ); + return; + } + if (argc == 4 && !strcmp( argv[2], "handles_dib" )) + { + test_handles_process_dib( argv[3] ); + return; + } + if (argc == 4 && !strcmp( argv[2], "string_data" )) + { + test_string_data_process( atoi( argv[3] )); + return; + } + if (argc == 3 && !strcmp( argv[2], "get_clipboard_data" )) + { + get_clipboard_data_process( ); + return; + } test_RegisterClipboardFormatA(); test_ClipboardOwner(); test_synthesized(); test_messages(); test_data_handles(); + test_GetUpdatedClipboardFormats(); + test_string_data(); } diff --git a/rostests/winetests/user32/combo.c b/rostests/winetests/user32/combo.c index 5c956a43c16..7c91f7f5c00 100644 --- a/rostests/winetests/user32/combo.c +++ b/rostests/winetests/user32/combo.c @@ -32,8 +32,8 @@ static HWND hMainWnd; #define expect_eq(expr, value, type, fmt); { type val = expr; ok(val == (value), #expr " expected " #fmt " got " #fmt "\n", (value), val); } #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \ - r.bottom == _bottom && r.right == _right, "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", \ - r.left, r.top, r.right, r.bottom, _left, _top, _right, _bottom); + r.bottom == _bottom && r.right == _right, "Invalid rect %s vs (%d,%d)-(%d,%d)\n", \ + wine_dbgstr_rect(&r), _left, _top, _right, _bottom); static HWND build_combo(DWORD style) { diff --git a/rostests/winetests/user32/cursoricon.c b/rostests/winetests/user32/cursoricon.c index 5f2306aee4f..61b32e01b6e 100644 --- a/rostests/winetests/user32/cursoricon.c +++ b/rostests/winetests/user32/cursoricon.c @@ -83,6 +83,7 @@ typedef struct { typedef struct { BYTE data[32*32*4]; + BYTE mask_data[32*32/8]; } ani_data32x32x32; typedef struct { @@ -2621,7 +2622,9 @@ static void test_monochrome_icon(void) CloseHandle(handle); handle = LoadImageA(NULL, "icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE); - ok(handle != NULL, "LoadImage() failed with %u.\n", GetLastError()); + ok(handle != NULL || + broken(use_core_info && handle == NULL), /* Win 8, 10 */ + "LoadImage() failed with %u.\n", GetLastError()); if (handle == NULL) { skip("Icon failed to load: %s, %s\n", diff --git a/rostests/winetests/user32/dce.c b/rostests/winetests/user32/dce.c index 0ee1283ef47..382d10a43ab 100755 --- a/rostests/winetests/user32/dce.c +++ b/rostests/winetests/user32/dce.c @@ -110,6 +110,12 @@ static void test_dc_attributes(void) } while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] ); + /* Released cache DCs are 'disabled' */ + rop = SetROP2( old_hdc, R2_BLACK ); + ok( rop == 0, "got %d\n", rop ); + rop = GetROP2( old_hdc ); + ok( rop == 0, "got %d\n", rop ); + /* test own DC */ hdc = GetDC( hwnd_owndc ); @@ -335,10 +341,8 @@ static void test_dc_visrgn(void) GetClipBox( hdc, &parent_rect ); ReleaseDC( hwnd_parent, hdc ); - ok( rect.left == parent_rect.left, "rect.left = %d, expected %d\n", rect.left, parent_rect.left ); - ok( rect.top == parent_rect.top, "rect.top = %d, expected %d\n", rect.top, parent_rect.top ); - ok( rect.right == parent_rect.right, "rect.right = %d, expected %d\n", rect.right, parent_rect.right ); - ok( rect.bottom == parent_rect.bottom, "rect.bottom = %d, expected %d\n", rect.bottom, parent_rect.bottom ); + ok( EqualRect( &rect, &parent_rect ), "rect = %s, expected %s\n", wine_dbgstr_rect( &rect ), + wine_dbgstr_rect( &parent_rect )); } diff --git a/rostests/winetests/user32/dialog.c b/rostests/winetests/user32/dialog.c index a639baa1c58..882e5a3ed94 100755 --- a/rostests/winetests/user32/dialog.c +++ b/rostests/winetests/user32/dialog.c @@ -1550,17 +1550,32 @@ static void test_timer_message(void) DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, timer_message_dlg_proc); } -static INT_PTR CALLBACK custom_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) { - if (msg == WM_INITDIALOG) - EndDialog(hdlg, 0); + if (code == HCBT_ACTIVATE) + { + HWND msgbox = (HWND)wParam, msghwnd; + char text[64]; - return FALSE; -} + if (msgbox) + { + text[0] = 0; + GetWindowTextA(msgbox, text, sizeof(text)); + ok(!strcmp(text, "MSGBOX caption"), "Unexpected window text \"%s\"\n", text); -static void test_dialog_custom_data(void) -{ - DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc); + msghwnd = GetDlgItem(msgbox, 0xffff); + ok(msghwnd != NULL, "Expected static control\n"); + + text[0] = 0; + GetWindowTextA(msghwnd, text, sizeof(text)); + ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text); + + SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0); + SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONUP, 0, 0); + } + } + + return CallNextHookEx(NULL, code, wParam, lParam); } struct create_window_params @@ -1623,9 +1638,18 @@ static void test_MessageBox(void) { MB_OK | MB_TASKMODAL, 0 }, { MB_OK | MB_SYSTEMMODAL, WS_EX_TOPMOST }, }; - DWORD tid, i; - HANDLE thread; struct create_window_params params; + HANDLE thread; + DWORD tid, i; + HHOOK hook; + int ret; + + hook = SetWindowsHookExA(WH_CBT, msgbox_hook_proc, NULL, GetCurrentThreadId()); + + ret = MessageBoxA(NULL, "Text", "MSGBOX caption", MB_OKCANCEL); + ok(ret == IDCANCEL, "got %d\n", ret); + + UnhookWindowsHookEx(hook); sprintf(params.caption, "pid %08x, tid %08x, time %08x", GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentTime()); @@ -1673,13 +1697,25 @@ static void test_MessageBox(void) } } +static INT_PTR CALLBACK custom_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) + EndDialog(hdlg, 0); + + return FALSE; +} + +static void test_dialog_custom_data(void) +{ + DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc); +} + START_TEST(dialog) { g_hinst = GetModuleHandleA (0); if (!RegisterWindowClasses()) assert(0); - test_MessageBox(); test_dialog_custom_data(); test_GetNextDlgItem(); test_IsDialogMessage(); @@ -1692,4 +1728,5 @@ START_TEST(dialog) test_MessageBoxFontTest(); test_SaveRestoreFocus(); test_timer_message(); + test_MessageBox(); } diff --git a/rostests/winetests/user32/input.c b/rostests/winetests/user32/input.c index 41d93e1213f..807a29adf2b 100755 --- a/rostests/winetests/user32/input.c +++ b/rostests/winetests/user32/input.c @@ -53,6 +53,8 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "wingdi.h" +#include "winnls.h" #include "wine/test.h" @@ -78,6 +80,7 @@ static struct { static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD); static UINT (WINAPI *pGetRawInputDeviceList) (PRAWINPUTDEVICELIST, PUINT, UINT); +static int (WINAPI *pGetWindowRgnBox)(HWND, LPRECT); #define MAXKEYEVENTS 12 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one @@ -162,6 +165,7 @@ static void init_function_pointers(void) GET_PROC(SendInput) GET_PROC(GetMouseMovePointsEx) GET_PROC(GetRawInputDeviceList) + GET_PROC(GetWindowRgnBox) #undef GET_PROC } @@ -1647,6 +1651,8 @@ static void test_ToUnicode(void) const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f, SC_A = 0x1e; const BYTE HIGHEST_BIT = 0x80; int i, ret; + BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409); + for(i=0; i<256; i++) state[i]=0; @@ -1673,7 +1679,10 @@ static void test_ToUnicode(void) if(!vk) { - short vk_ret = VkKeyScanW(utests[i].chr); + short vk_ret; + + if (!us_kbd) continue; + vk_ret = VkKeyScanW(utests[i].chr); if (vk_ret == -1) continue; vk = vk_ret & 0xff; if (vk_ret & 0x100) mod |= shift; @@ -1921,9 +1930,16 @@ static void test_Input_mouse(void) struct thread_data thread_data; HANDLE thread; DWORD thread_id; - POINT pt; + WNDCLASSA wclass; + POINT pt, pt_org; + int region_type; + HRGN hregion; + RECT region; + BOOL ret; MSG msg; + GetCursorPos(&pt_org); + button_win = CreateWindowA("button", "button", WS_VISIBLE | WS_POPUP, 100, 100, 100, 100, 0, NULL, NULL, NULL); ok(button_win != 0, "CreateWindow failed\n"); @@ -2124,6 +2140,224 @@ static void test_Input_mouse(void) DestroyWindow(hwnd); ok(ReleaseCapture(), "ReleaseCapture failed\n"); + wclass.style = 0; + wclass.lpfnWndProc = WndProc; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + wclass.hInstance = GetModuleHandleA(NULL); + wclass.hIcon = LoadIconA(0, (LPCSTR)IDI_APPLICATION); + wclass.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + wclass.hbrBackground = CreateSolidBrush(RGB(128, 128, 128)); + wclass.lpszMenuName = NULL; + wclass.lpszClassName = "InputLayeredTestClass"; + RegisterClassA( &wclass ); + + /* click through layered window with alpha channel / color key */ + hwnd = CreateWindowA(wclass.lpszClassName, "InputLayeredTest", + WS_VISIBLE | WS_POPUP, 100, 100, 100, 100, button_win, NULL, NULL, NULL); + ok(hwnd != NULL, "CreateWindowEx failed\n"); + + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); + ret = SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA); + ok(ret, "SetLayeredWindowAttributes failed\n"); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + + if (pGetWindowRgnBox) + { + region_type = pGetWindowRgnBox(hwnd, ®ion); + ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); + } + + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + ret = SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA); + ok(ret, "SetLayeredWindowAttributes failed\n"); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + + if (pGetWindowRgnBox) + { + region_type = pGetWindowRgnBox(hwnd, ®ion); + ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); + } + + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + todo_wine + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + todo_wine + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(got_button_down || broken(!got_button_down), "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + ret = SetLayeredWindowAttributes(hwnd, RGB(0, 255, 0), 255, LWA_ALPHA | LWA_COLORKEY); + ok(ret, "SetLayeredWindowAttributes failed\n"); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + + if (pGetWindowRgnBox) + { + region_type = pGetWindowRgnBox(hwnd, ®ion); + ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); + } + + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + ret = SetLayeredWindowAttributes(hwnd, RGB(128, 128, 128), 0, LWA_COLORKEY); + ok(ret, "SetLayeredWindowAttributes failed\n"); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + + if (pGetWindowRgnBox) + { + region_type = pGetWindowRgnBox(hwnd, ®ion); + ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); + } + + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + + if (pGetWindowRgnBox) + { + region_type = pGetWindowRgnBox(hwnd, ®ion); + ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); + } + + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + hregion = CreateRectRgn(0, 0, 10, 10); + ok(hregion != NULL, "CreateRectRgn failed\n"); + ret = SetWindowRgn(hwnd, hregion, TRUE); + ok(ret, "SetWindowRgn failed\n"); + DeleteObject(hregion); + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(1000); + + if (pGetWindowRgnBox) + { + region_type = pGetWindowRgnBox(hwnd, ®ion); + ok(region_type == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", region_type); + } + + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) + { + DispatchMessageA(&msg); + + if (msg.message == WM_LBUTTONDOWN) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_down = TRUE; + } + else if (msg.message == WM_LBUTTONUP) + { + ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); + got_button_up = TRUE; + break; + } + } + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + + DestroyWindow(hwnd); + SetCursorPos(pt_org.x, pt_org.y); + CloseHandle(thread_data.start_event); CloseHandle(thread_data.end_event); DestroyWindow(button_win); @@ -2493,6 +2727,36 @@ static void test_GetKeyState(void) CloseHandle(semaphores[1]); } +static void test_OemKeyScan(void) +{ + DWORD ret, expect, vkey, scan; + WCHAR oem, wchr; + char oem_char; + + for (oem = 0; oem < 0x200; oem++) + { + ret = OemKeyScan( oem ); + + oem_char = LOBYTE( oem ); + if (!OemToCharBuffW( &oem_char, &wchr, 1 )) + expect = -1; + else + { + vkey = VkKeyScanW( wchr ); + scan = MapVirtualKeyW( LOBYTE( vkey ), MAPVK_VK_TO_VSC ); + if (!scan) + expect = -1; + else + { + vkey &= 0xff00; + vkey <<= 8; + expect = vkey | scan; + } + } + ok( ret == expect, "%04x: got %08x expected %08x\n", oem, ret, expect ); + } +} + START_TEST(input) { init_function_pointers(); @@ -2516,6 +2780,7 @@ START_TEST(input) test_key_names(); test_attach_input(); test_GetKeyState(); + test_OemKeyScan(); if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx(); diff --git a/rostests/winetests/user32/menu.c b/rostests/winetests/user32/menu.c index 90d1e443403..4323ae701ba 100755 --- a/rostests/winetests/user32/menu.c +++ b/rostests/winetests/user32/menu.c @@ -2463,6 +2463,7 @@ static void test_menu_input(void) { HANDLE hThread, hWnd; DWORD tid; ATOM aclass; + POINT orig_pos; if (!pSendInput) { @@ -2507,6 +2508,8 @@ static void test_menu_input(void) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); + GetCursorPos(&orig_pos); + hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid); while(1) { @@ -2514,6 +2517,7 @@ static void test_menu_input(void) { break; while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); } + SetCursorPos(orig_pos.x, orig_pos.y); DestroyWindow(hWnd); } diff --git a/rostests/winetests/user32/monitor.c b/rostests/winetests/user32/monitor.c index 7a039e5ad4e..886d63ccfe2 100644 --- a/rostests/winetests/user32/monitor.c +++ b/rostests/winetests/user32/monitor.c @@ -89,12 +89,12 @@ static void test_enumdisplaydevices(void) } dd.cb = sizeof(dd); - while(1) + for (num = 0;; num++) { - BOOL ret; HDC dc; ret = pEnumDisplayDevicesA(NULL, num, &dd, 0); if(!ret) break; + if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { strcpy(primary_device_name, dd.DeviceName); @@ -107,7 +107,6 @@ static void test_enumdisplaydevices(void) ok(dc != NULL, "Failed to CreateDC(\"%s\") err=%d\n", dd.DeviceName, GetLastError()); DeleteDC(dc); } - num++; } if (primary_num == -1 || !pEnumDisplayMonitors || !pGetMonitorInfoA) @@ -122,6 +121,17 @@ static void test_enumdisplaydevices(void) ok(!strcmp(primary_monitor_device_name, primary_device_name), "monitor device name %s, device name %s\n", primary_monitor_device_name, primary_device_name); + + dd.cb = sizeof(dd); + for (num = 0;; num++) + { + ret = pEnumDisplayDevicesA(primary_device_name, num, &dd, 0); + if (!ret) break; + + dd.DeviceID[63] = 0; + ok(!strcasecmp(dd.DeviceID, "Monitor\\Default_Monitor\\{4D36E96E-E325-11CE-BFC1-08002BE10318}\\"), + "DeviceID \"%s\" does not start with \"Monitor\\Default_Monitor\\...\" prefix\n", dd.DeviceID); + } } struct vid_mode @@ -131,9 +141,9 @@ struct vid_mode }; static const struct vid_mode vid_modes_test[] = { - {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY, 1}, + {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY, 0}, {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY, 1}, - {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL , 1}, + {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL , 0}, {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT , 1}, {640, 480, 0, 0, DM_BITSPERPEL , 0}, {640, 480, 0, 0, DM_DISPLAYFREQUENCY, 0}, diff --git a/rostests/winetests/user32/msg.c b/rostests/winetests/user32/msg.c index 6f0dd17920b..e0512ffa081 100755 --- a/rostests/winetests/user32/msg.c +++ b/rostests/winetests/user32/msg.c @@ -122,6 +122,8 @@ static DWORD cbt_hook_thread_id; static const WCHAR testWindowClassW[] = { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 }; +static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM); + /* FIXME: add tests for these Window Edge Styles (Win31/Win95/98 look), in order of precedence: @@ -773,7 +775,7 @@ static const struct message WmCreateInvisibleMaxPopupSeq[] = { { 0 } }; /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */ -static const struct message WmShowMaxPopupResizedSeq[] = { +static const struct message WmShowMaxPopupResizedSeq_todo[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED }, @@ -804,6 +806,37 @@ static const struct message WmShowMaxPopupResizedSeq[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } }; +static const struct message WmShowMaxPopupResizedSeq[] = { + { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, + { WM_GETMINMAXINFO, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED }, + { WM_NCCALCSIZE, sent|wparam, TRUE }, + { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent|wparam, 1 }, + { HCBT_SETFOCUS, hook }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, + { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */ + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent }, + /* WinNT4.0 sends WM_MOVE */ + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { 0 } +}; /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */ static const struct message WmShowMaxPopupSeq[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, @@ -942,6 +975,242 @@ static const struct message WmShowVisiblePopupSeq_3[] = { { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW }, { 0 } }; +/* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location) + */ +static const struct message WmShowPopupExtremeLocationSeq[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent }, + { HCBT_ACTIVATE, hook }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent }, + /* occasionally received on test machines */ + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { 0 } +}; +/* CreateWindow (for a popup window with WS_VISIBLE style set) + */ +static const struct message WmShowPopupFirstDrawSeq_1[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_SHOWWINDOW, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent }, + { HCBT_ACTIVATE, hook }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_PAINT, sent }, + /* occasionally received on test machines */ + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, + { 0 } +}; +/* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED)) + */ +static const struct message WmShowPopupFirstDrawSeq_2[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, + { WM_GETMINMAXINFO, sent }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED }, + { WM_NCCALCSIZE, sent|wparam, TRUE }, + { HCBT_ACTIVATE, hook }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_NCPAINT, sent|optional|wparam, 1 }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc, 0 }, + { WM_PAINT, sent}, + /* occasionally received on test machines */ + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, + { 0 } +}; +static const struct message WmFirstDrawSetWindowPosSeq1[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_WINDOWPOSCHANGING, sent }, + { HCBT_ACTIVATE, hook }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_MOVE, sent|defwinproc }, + { 0 } +}; +static const struct message WmFirstDrawSetWindowPosSeq2[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_WINDOWPOSCHANGING, sent }, + { HCBT_ACTIVATE, hook }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_MOVE, sent|defwinproc }, + { 0 } +}; +static const struct message WmFirstDrawSetWindowPosSeq3[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { HCBT_ACTIVATE, hook|optional }, + /* Probably shouldn't happen, but not part of this test */ + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent|optional }, + { WM_NCACTIVATE, sent|optional }, + { WM_ACTIVATE, sent|optional }, + { HCBT_SETFOCUS, hook|optional }, + { WM_SETFOCUS, sent|defwinproc|optional }, + { 0 } +}; +static const struct message WmFirstDrawSetWindowPosSeq4[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_WINDOWPOSCHANGING, sent }, + { HCBT_ACTIVATE, hook }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_NCPAINT, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent }, + { 0 } +}; +static const struct message WmFirstDrawSetWindowPosSeq5[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_WINDOWPOSCHANGING, sent }, + { HCBT_ACTIVATE, hook }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_ACTIVATEAPP, sent }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent }, + { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_WINDOWPOSCHANGED, sent }, + { 0 } +}; +static const struct message WmFirstDrawChildSeq1[] = { + { 0 } +}; +static const struct message WmFirstDrawChildSeq2[] = { + { WM_NCPAINT, sent|wparam, 1 }, + { WM_ERASEBKGND, sent }, + /* occasionally received on test machines */ + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { 0 } +}; /* CreateWindow (for child window, not initially visible) */ static const struct message WmCreateChildSeq[] = { { HCBT_CREATEWND, hook }, @@ -1543,12 +1812,25 @@ static const struct message WmEnableWindowSeq_1[] = }; static const struct message WmEnableWindowSeq_2[] = +{ + { WM_CANCELMODE, sent|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { 0 } +}; + +static const struct message WmEnableWindowSeq_3[] = { { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, { WM_ENABLE, sent|wparam|lparam, TRUE, 0 }, { 0 } }; +static const struct message WmEnableWindowSeq_4[] = +{ + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { 0 } +}; + static const struct message WmGetScrollRangeSeq[] = { { SBM_GETRANGE, sent }, @@ -1690,6 +1972,10 @@ static const struct message WmTrackPopupMenu[] = { { 0 } }; +static const struct message WmTrackPopupMenuEsc[] = { + { 0 } +}; + static const struct message WmTrackPopupMenuCapture[] = { { HCBT_CREATEWND, hook }, { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 }, @@ -1958,18 +2244,59 @@ static void add_message_(int line, const struct recvd_message *msg) { MEASURE_ITEM_STRUCT mi; MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam; + BOOL is_unicode_data = TRUE; sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx", msg->descr, msg->hwnd, mis->CtlType, mis->CtlID, mis->itemID, mis->itemData); + if (mis->CtlType == ODT_LISTBOX) + { + HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID); + is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS; + } + mi.u.wp = 0; mi.u.item.CtlType = mis->CtlType; mi.u.item.CtlID = mis->CtlID; mi.u.item.itemID = mis->itemID; mi.u.item.wParam = msg->wParam; seq->wParam = mi.u.wp; - seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0; + if (is_unicode_data) + seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0; + else + seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0; + break; + } + + case WM_COMPAREITEM: + { + COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam; + HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID); + BOOL is_unicode_data = TRUE; + + ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam); + ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem); + ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1); + ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2); + + sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx", + msg->descr, msg->hwnd, cis->CtlType, cis->CtlID, + cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2); + + if (cis->CtlType == ODT_LISTBOX) + is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS; + + if (is_unicode_data) + { + seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0; + seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0; + } + else + { + seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0; + seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0; + } break; } @@ -4426,6 +4753,18 @@ static void test_showwindow(void) DestroyWindow(hwnd); flush_sequence(); + /* Test again, this time the NC_PAINT message */ + hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (hwnd != 0, "Failed to create popup window\n"); + SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE); + flush_sequence(); + ShowWindow(hwnd, SW_SHOWMAXIMIZED); + ok_sequence(WmShowMaxPopupResizedSeq_todo, + "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE); + DestroyWindow(hwnd); + flush_sequence(); + /* Test 2: * 1. Create invisible maximized popup window. * 2. Show it maximized. @@ -4754,6 +5093,23 @@ static DWORD CALLBACK show_window_thread(LPVOID arg) return 0; } +/* Helper function to easier test SetWindowPos messages */ +#define test_msg_setpos( expected_list, flags, todo ) \ + test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__) +static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line) +{ + HWND hwnd; + + flush_events(); + flush_sequence(); + hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP, + 10, 10, 100, 100, NULL, 0, 0, NULL ); + ok (hwnd != 0, "Failed to create popup window\n"); + SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags); + ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line); + DestroyWindow(hwnd); +} + /* test if we receive the right sequence of messages */ static void test_messages(void) { @@ -4880,6 +5236,116 @@ static void test_messages(void) DestroyWindow(hwnd); ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE); + /* Test if windows are correctly drawn when first shown */ + + /* Visible, redraw */ + flush_events(); + flush_sequence(); + hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE, + 10, 10, 100, 100, NULL, 0, 0, NULL ); + ok (hwnd != 0, "Failed to create popup window\n"); + RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW); + ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE); + DestroyWindow(hwnd); + + /* Invisible, show, message */ + flush_events(); + flush_sequence(); + hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP, + 10, 10, 100, 100, NULL, 0, 0, NULL ); + ok (hwnd != 0, "Failed to create popup window\n"); + ShowWindow(hwnd, SW_SHOW); + SendMessageW(hwnd, WM_PAINT, 0, 0); + ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE); + DestroyWindow(hwnd); + + /* Invisible, show maximized, redraw */ + flush_events(); + flush_sequence(); + hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP, + 10, 10, 100, 100, NULL, 0, 0, NULL ); + ok (hwnd != 0, "Failed to create popup window\n"); + ShowWindow(hwnd, SW_SHOWMAXIMIZED); + RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW); + ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE); + DestroyWindow(hwnd); + + /* Test SetWindowPos */ + test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, + SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE); + + test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE); + + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE); + + test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE); + + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE); + test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE); + + /* Test SetWindowPos with child windows */ + flush_events(); + hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (hparent != 0, "Failed to create parent window\n"); + + hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE, + 0, 0, 10, 10, hparent, 0, 0, NULL); + ok (hchild != 0, "Failed to create child window\n"); + flush_sequence(); + SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW); + ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */ + "SetWindowPos:show_popup_first_show_window_child1", FALSE); + DestroyWindow(hchild); + DestroyWindow(hparent); + + flush_events(); + hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (hparent != 0, "Failed to create parent window\n"); + + hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE, + 0, 0, 10, 10, hparent, 0, 0, NULL); + ok (hchild != 0, "Failed to create child window\n"); + flush_sequence(); + SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW); + ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */ + "SetWindowPos:show_popup_first_show_window_child2", FALSE); + DestroyWindow(hchild); + DestroyWindow(hparent); + + /* Test message sequence for extreme position and size */ + + flush_sequence(); + hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE, + -10, -10, 10000, 10000, NULL, 0, 0, NULL ); + ok (hwnd != 0, "Failed to create popup window\n"); + ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE); + DestroyWindow(hwnd); + + + /* Test child windows */ + hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hparent != 0, "Failed to create parent window\n"); @@ -5128,8 +5594,14 @@ static void test_messages(void) EnableWindow(hparent, FALSE); ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE); + EnableWindow(hparent, FALSE); + ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE); + EnableWindow(hparent, TRUE); - ok_sequence(WmEnableWindowSeq_2, "EnableWindow(TRUE)", FALSE); + ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE); + + EnableWindow(hparent, TRUE); + ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE); flush_events(); flush_sequence(); @@ -5704,6 +6176,23 @@ static const struct message WmClearStateButtonSeq[] = { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; +static const struct message WmDisableButtonSeq[] = +{ + { WM_LBUTTONDOWN, sent }, + { BM_SETSTATE, sent|defwinproc }, + { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, + { WM_CTLCOLORBTN, sent|optional }, + { WM_LBUTTONUP, sent }, + { BM_SETSTATE, sent|defwinproc }, + { WM_CTLCOLORBTN, sent|defwinproc|optional }, + { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, + { BM_SETCHECK, sent|defwinproc|optional }, + { WM_CTLCOLORBTN, sent|optional }, + { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, + { WM_CAPTURECHANGED, sent|defwinproc }, + { WM_COMMAND, sent }, + { 0 } +}; static const struct message WmClearStateOwnerdrawSeq[] = { { BM_SETSTATE, sent }, @@ -5743,7 +6232,24 @@ static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, case BM_SETSTATE: if (GetCapture()) ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture()); + + lParam = (ULONG_PTR)GetMenu(hwnd); + goto log_it; + + case WM_GETDLGCODE: + if (lParam) + { + MSG *msg = (MSG *)lParam; + lParam = MAKELPARAM(msg->message, msg->wParam); + } + wParam = (ULONG_PTR)GetMenu(hwnd); + goto log_it; + + case BM_SETCHECK: + case BM_GETCHECK: + lParam = (ULONG_PTR)GetMenu(hwnd); /* fall through */ +log_it: default: msg.hwnd = hwnd; msg.message = message; @@ -5850,10 +6356,11 @@ static void test_button_messages(void) WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq, WmSetTextButtonSeq }, }; + LOGFONTA logfont = { 0 }; + HFONT zfont, hfont2; unsigned int i; HWND hwnd, parent; DWORD dlg_code; - HFONT zfont; /* selection with VK_SPACE should capture button window */ hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP, @@ -5872,11 +6379,21 @@ static void test_button_messages(void) 100, 100, 200, 200, 0, 0, 0, NULL); ok(parent != 0, "Failed to create parent window\n"); + memset(&logfont, 0, sizeof(logfont)); + logfont.lfHeight = -12; + logfont.lfWeight = FW_NORMAL; + strcpy(logfont.lfFaceName, "Tahoma"); + + hfont2 = CreateFontIndirectA(&logfont); + ok(hfont2 != NULL, "Failed to create Tahoma font\n"); + for (i = 0; i < sizeof(button)/sizeof(button[0]); i++) { MSG msg; DWORD style, state; + HFONT prevfont; char desc[64]; + HDC hdc; trace("button style %08x\n", button[i].style); @@ -6051,15 +6568,484 @@ static void test_button_messages(void) ok_sequence(button[i].lbuttonup, desc, FALSE); flush_sequence(); - zfont = GetStockObject(SYSTEM_FONT); + zfont = GetStockObject(DEFAULT_GUI_FONT); SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE); UpdateWindow(hwnd); sprintf(desc, "button[%i]: WM_SETFONT on a button", i); ok_sequence(button[i].setfont, desc, FALSE); + /* Test that original font is not selected back after painting */ + hdc = CreateCompatibleDC(0); + + prevfont = SelectObject(hdc, hfont2); + ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n"); + SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0); + todo_wine + ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i); + SelectObject(hdc, prevfont); + + prevfont = SelectObject(hdc, hfont2); + ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n"); + SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0); + todo_wine + ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i); + SelectObject(hdc, prevfont); + + DeleteDC(hdc); + DestroyWindow(hwnd); } + DeleteObject(hfont2); + DestroyWindow(parent); + + /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */ + + parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (hwnd != 0, "Failed to create overlapped window\n"); + + hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, + 0, 0, 50, 14, parent, 0, 0, NULL); + + EnableWindow(hwnd, FALSE); + flush_sequence(); + SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0); + SendMessageA(hwnd, WM_LBUTTONUP, 0, 0); + ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE); + + DestroyWindow(hwnd); + DestroyWindow(parent); +} + +#define ID_RADIO1 501 +#define ID_RADIO2 502 +#define ID_RADIO3 503 +#define ID_TEXT 504 + +static const struct message auto_radio_button_BM_CLICK[] = +{ + { BM_CLICK, sent|wparam|lparam, 0, 0 }, + { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 }, + { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 }, + { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 }, + { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 }, + { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) }, + { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { 0 } +}; + +static const struct message auto_radio_button_VK_UP_child[] = +{ + { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 }, + { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 }, + { 0 } +}; + +static const struct message auto_radio_button_VK_UP_parent[] = +{ + { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 }, + { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 }, + { 0 } +}; + +static const struct message auto_radio_button_VK_UP_dialog[] = +{ + { WM_GETDLGCODE, sent|parent, 0, 0 }, + + /* optional trailer seen on some windows setups */ + { WM_CHANGEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_CTLCOLORBTN, sent|parent|optional }, + { WM_CTLCOLORBTN, sent|parent|optional }, + { WM_UPDATEUISTATE, sent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { WM_CTLCOLORSTATIC, sent|parent|optional }, + { 0 } +}; + +static const struct message auto_radio_button_VK_DOWN_dialog[] = +{ + { WM_GETDLGCODE, sent|parent, 0, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) }, + { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_KILLFOCUS, sent, 0, 0 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent, 0, 0 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) }, + { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 }, + { WM_GETDLGCODE, sent|parent, 0, 0 }, + { DM_GETDEFID, sent|parent, 0, 0 }, + { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 }, + { BM_CLICK, sent|wparam|lparam, 1, 0 }, + { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 }, + { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 }, + { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 }, + { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 }, + { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 }, + { WM_CTLCOLORSTATIC, sent|parent }, + { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) }, + { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { WM_PAINT, sent }, + { WM_CTLCOLORSTATIC, sent|parent }, + { 0 } +}; + +static const struct message auto_radio_button_VK_DOWN_radio3[] = +{ + { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 }, + { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 }, + { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 }, + { WM_GETDLGCODE, sent|parent, 0, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) }, + { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 }, + { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 }, + { WM_USER, sent|parent, 0, 0 }, + { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 }, + { 0 } +}; + +static const struct message auto_radio_button_VK_UP_radio1[] = +{ + { WM_GETDLGCODE, sent|parent, 0, 0 }, + { 0 } +}; + +static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + ParentMsgCheckProcA(hwnd, msg, wp, lp); + return 1; +} + +static void test_autoradio_BM_CLICK(void) +{ + HWND parent, radio1, radio2, radio3; + RECT rc; + MSG msg; + DWORD ret; + + subclass_button(); + + parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0); + ok(parent != 0, "failed to create parent window\n"); + + radio1 = GetDlgItem(parent, ID_RADIO1); + radio2 = GetDlgItem(parent, ID_RADIO2); + radio3 = GetDlgItem(parent, ID_RADIO3); + + /* this avoids focus messages in the generated sequence */ + SetFocus(radio2); + + flush_events(); + flush_sequence(); + + ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + + SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0); + + ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + + SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0); + + ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + + SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0); + + ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + + GetWindowRect(radio2, &rc); + SetCursorPos(rc.left+1, rc.top+1); + + flush_events(); + flush_sequence(); + + log_all_parent_messages++; + + SendMessageA(radio2, BM_CLICK, 0, 0); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE); + + log_all_parent_messages--; + + ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); + ok(ret == BST_CHECKED, "got %08x\n", ret); + ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); + ok(ret == BST_UNCHECKED, "got %08x\n", ret); + + DestroyWindow(parent); +} + +#define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__) +static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line) +{ + DWORD ret; + + ret = SendMessageA(radio1, BM_GETCHECK, 0, 0); + ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret); + ret = SendMessageA(radio2, BM_GETCHECK, 0, 0); + ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret); + ret = SendMessageA(radio3, BM_GETCHECK, 0, 0); + ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret); +} + +static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3) +{ + SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0); + SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0); + SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0); +} + +static void test_autoradio_kbd_move(void) +{ + HWND parent, radio1, radio2, radio3, hwnd; + RECT rc; + MSG msg; + DWORD ret; + + subclass_button(); + + parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0); + ok(parent != 0, "failed to create parent window\n"); + + radio1 = GetDlgItem(parent, ID_RADIO1); + radio2 = GetDlgItem(parent, ID_RADIO2); + radio3 = GetDlgItem(parent, ID_RADIO3); + + flush_events(); + flush_sequence(); + + test_radio(radio1, 0, radio2, 0, radio3, 0); + set_radio(radio1, 1, radio2, 1, radio3, 1); + test_radio(radio1, 1, radio2, 1, radio3, 1); + + SetFocus(radio3); + + flush_events(); + flush_sequence(); + + log_all_parent_messages++; + + SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0); + SendMessageA(radio3, WM_KEYUP, VK_UP, 0); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE); + + test_radio(radio1, 1, radio2, 1, radio3, 1); + + flush_events(); + flush_sequence(); + + DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0); + DefDlgProcA(parent, WM_KEYUP, VK_UP, 0); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE); + + test_radio(radio1, 1, radio2, 1, radio3, 1); + + SetFocus(radio3); + GetWindowRect(radio3, &rc); + + flush_events(); + flush_sequence(); + + msg.hwnd = parent; + msg.message = WM_KEYDOWN; + msg.wParam = VK_UP; + msg.lParam = 0; + msg.pt.x = rc.left + 1; + msg.pt.y = rc.top + 1; + ret = IsDialogMessageA(parent, &msg); + ok(ret, "IsDialogMessage should return TRUE\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); +if (0) /* actual message sequence is different on every run in some Windows setups */ + ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE); + /* what really matters is that nothing has changed */ + test_radio(radio1, 1, radio2, 1, radio3, 1); + + set_radio(radio1, 0, radio2, 1, radio3, 1); + test_radio(radio1, 0, radio2, 1, radio3, 1); + + flush_events(); + flush_sequence(); + + ret = IsDialogMessageA(parent, &msg); + ok(ret, "IsDialogMessage should return TRUE\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); +if (0) /* actual message sequence is different on every run in some Windows setups */ + ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE); + /* what really matters is that nothing has changed */ + test_radio(radio1, 0, radio2, 1, radio3, 1); + + /* switch from radio3 ro radio1 */ + SetFocus(radio3); + GetWindowRect(radio3, &rc); + + flush_events(); + flush_sequence(); + + msg.hwnd = parent; + msg.message = WM_KEYDOWN; + msg.wParam = VK_DOWN; + msg.lParam = 0; + msg.pt.x = rc.left + 1; + msg.pt.y = rc.top + 1; + ret = IsDialogMessageA(parent, &msg); + ok(ret, "IsDialogMessage should return TRUE\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE); + + test_radio(radio1, 1, radio2, 0, radio3, 0); + + hwnd = GetFocus(); + ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd); + GetWindowRect(radio1, &rc); + + msg.hwnd = parent; + msg.message = WM_KEYDOWN; + msg.wParam = VK_DOWN; + msg.lParam = 0; + msg.pt.x = rc.left + 1; + msg.pt.y = rc.top + 1; + ret = IsDialogMessageA(parent, &msg); + ok(ret, "IsDialogMessage should return TRUE\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE); + + test_radio(radio1, 1, radio2, 0, radio3, 0); + + hwnd = GetFocus(); + ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd); + + flush_events(); + flush_sequence(); + + msg.hwnd = parent; + msg.message = WM_KEYDOWN; + msg.wParam = VK_UP; + msg.lParam = 0; + msg.pt.x = rc.left + 1; + msg.pt.y = rc.top + 1; + ret = IsDialogMessageA(parent, &msg); + ok(ret, "IsDialogMessage should return TRUE\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE); + + test_radio(radio1, 1, radio2, 0, radio3, 0); + + hwnd = GetFocus(); + ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd); + + flush_events(); + flush_sequence(); + + msg.hwnd = parent; + msg.message = WM_KEYDOWN; + msg.wParam = VK_UP; + msg.lParam = 0; + msg.pt.x = rc.left + 1; + msg.pt.y = rc.top + 1; + ret = IsDialogMessageA(parent, &msg); + ok(ret, "IsDialogMessage should return TRUE\n"); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); +if (0) /* actual message sequence is different on every run in some Windows setups */ + ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE); + /* what really matters is that nothing has changed */ + test_radio(radio1, 1, radio2, 0, radio3, 0); + + log_all_parent_messages--; + DestroyWindow(parent); } @@ -6517,7 +7503,7 @@ void dump_region(HRGN hrgn) GetRegionData( hrgn, size, data ); printf("%d rects:", data->rdh.nCount ); for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++) - printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom ); + printf( " %s", wine_dbgstr_rect( rect )); printf("\n"); HeapFree( GetProcessHeap(), 0, data ); } @@ -6698,7 +7684,7 @@ static const struct message WmSetParentStyle[] = { static void test_paint_messages(void) { BOOL ret; - RECT rect; + RECT rect, rect2; POINT pt; MSG msg; HWND hparent, hchild; @@ -6763,7 +7749,8 @@ static void test_paint_messages(void) */ trace("testing ValidateRect(0, NULL)\n"); SetRectEmpty( &rect ); - if (ValidateRect(0, &rect)) /* not supported on Win9x */ + if (ValidateRect(0, &rect) && /* not supported on Win9x */ + GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */ { check_update_rgn( hwnd, hrgn ); ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); @@ -7237,15 +8224,21 @@ static void test_paint_messages(void) SetRectRgn( hrgn, 10, 10, 40, 40 ); check_update_rgn( hchild, hrgn ); MoveWindow( hparent, -20, -20, 200, 200, FALSE ); - SetRectRgn( hrgn, 20, 20, 100, 100 ); + GetUpdateRect( hparent, &rect2, FALSE ); + if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */ + { + rect.left += 20; + rect.top += 20; + } + SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom ); check_update_rgn( hparent, hrgn ); - SetRectRgn( hrgn, 30, 30, 40, 40 ); + SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 ); check_update_rgn( hchild, hrgn ); /* invalidated region is cropped by the parent rects */ SetRect( &rect, 0, 0, 50, 50 ); RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE ); - SetRectRgn( hrgn, 30, 30, 50, 50 ); + SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 ); check_update_rgn( hchild, hrgn ); DestroyWindow( hparent ); @@ -8327,7 +9320,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam message == WM_PARENTNOTIFY || message == WM_CANCELMODE || message == WM_SETFOCUS || message == WM_KILLFOCUS || message == WM_ENABLE || message == WM_ENTERIDLE || - message == WM_DRAWITEM || message == WM_MEASUREITEM || + message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM || message == WM_COMMAND || message == WM_IME_SETCONTEXT) { switch (message) @@ -8375,7 +9368,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam ret = DefWindowProcA(hwnd, message, wParam, lParam); defwndproc_counter--; - return ret; + return message == WM_COMPAREITEM ? -1 : ret; } static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) @@ -11154,8 +12147,9 @@ static void test_PeekMessage3(void) PostMessageA(hwnd, WM_USER + 1, 0, 0); PostMessageA(hwnd, WM_USER, 0, 0); ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); - todo_wine ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); + ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE); + ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message); ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); @@ -12125,9 +13119,8 @@ static void test_ShowWindow(void) SetLastError(0xdeadbeef); ret = pGetMonitorInfoA(hmon, &mi); ok(ret, "GetMonitorInfo error %u\n", GetLastError()); - trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n", - mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, - mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom); + trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor), + wine_dbgstr_rect(&mi.rcWork)); work_rc = mi.rcWork; } @@ -12145,11 +13138,8 @@ static void test_ShowWindow(void) ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1, "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y); todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */ - ok(EqualRect(&win_rc, &wp.rcNormalPosition), - "expected %d,%d-%d,%d got %d,%d-%d,%d\n", - win_rc.left, win_rc.top, win_rc.right, win_rc.bottom, - wp.rcNormalPosition.left, wp.rcNormalPosition.top, - wp.rcNormalPosition.right, wp.rcNormalPosition.bottom); + ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc), + wine_dbgstr_rect(&wp.rcNormalPosition)); for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++) { @@ -12201,11 +13191,8 @@ static void test_ShowWindow(void) "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y); if (0) /* FIXME: Wine behaves completely different here */ - ok(EqualRect(&win_rc, &wp.rcNormalPosition), - "expected %d,%d-%d,%d got %d,%d-%d,%d\n", - win_rc.left, win_rc.top, win_rc.right, win_rc.bottom, - wp.rcNormalPosition.left, wp.rcNormalPosition.top, - wp.rcNormalPosition.right, wp.rcNormalPosition.bottom); + ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", + wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition)); } DestroyWindow(hwnd); flush_events(); @@ -12230,6 +13217,8 @@ static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPAR switch (message) { case WM_INITDIALOG: + return lParam; + case WM_GETDLGCODE: return 0; } @@ -12338,6 +13327,20 @@ static const struct message WmDefDlgSetFocus_2[] = { { 0 } }; /* Creation of a dialog */ +static const struct message WmCreateDialogParamSeq_0[] = { + { HCBT_CREATEWND, hook }, + { WM_NCCREATE, sent }, + { WM_NCCALCSIZE, sent|wparam, 0 }, + { WM_CREATE, sent }, + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_MOVE, sent }, + { WM_SETFONT, sent }, + { WM_INITDIALOG, sent }, + { WM_CHANGEUISTATE, sent|optional }, + { 0 } +}; +/* Creation of a dialog */ static const struct message WmCreateDialogParamSeq_1[] = { { HCBT_CREATEWND, hook }, { WM_NCCREATE, sent }, @@ -12348,6 +13351,16 @@ static const struct message WmCreateDialogParamSeq_1[] = { { WM_MOVE, sent }, { WM_SETFONT, sent }, { WM_INITDIALOG, sent }, + { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */ + { HCBT_SETFOCUS, hook }, + { HCBT_ACTIVATE, hook }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_PALETTEISCHANGING, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, + { WM_ACTIVATE, sent|wparam, 1 }, + { WM_SETFOCUS, sent }, { WM_CHANGEUISTATE, sent|optional }, { 0 } }; @@ -12511,9 +13524,24 @@ static void test_dialog_messages(void) cls.lpfnWndProc = test_dlg_proc; if (!RegisterClassA(&cls)) assert(0); + SetFocus(0); + flush_sequence(); hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0); ok(IsWindow(hdlg), "CreateDialogParam failed\n"); + ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE); + hfocus = GetFocus(); + ok(hfocus == 0, "wrong focus %p\n", hfocus); + EndDialog(hdlg, 0); + DestroyWindow(hdlg); + flush_sequence(); + + SetFocus(0); + flush_sequence(); + hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1); + ok(IsWindow(hdlg), "CreateDialogParam failed\n"); ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE); + hfocus = GetFocus(); + ok(hfocus == hdlg, "wrong focus %p\n", hfocus); EndDialog(hdlg, 0); DestroyWindow(hdlg); flush_sequence(); @@ -13461,6 +14489,19 @@ static const struct message wm_lb_addstring[] = { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef }, { 0 } }; +static const struct message wm_lb_addstring_sort[] = +{ + { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed }, + { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed }, + { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee }, + { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee }, + { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee }, + { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef }, + { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef }, + { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef }, + { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef }, + { 0 } +}; #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__) @@ -13526,6 +14567,7 @@ static void test_listbox_messages(void) parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); + /* with LBS_HASSTRINGS */ listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL, WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE, 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); @@ -13606,6 +14648,32 @@ static void test_listbox_messages(void) log_all_parent_messages--; + DestroyWindow(listbox); + + /* with LBS_SORT and without LBS_HASSTRINGS */ + listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL, + WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE, + 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL); + listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc); + + check_lb_state(listbox, 0, LB_ERR, 0, 0); + + flush_sequence(); + + log_all_parent_messages++; + + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0"); + ok(ret == 0, "expected 0, got %ld\n", ret); + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1"); + ok(ret == 1, "expected 1, got %ld\n", ret); + ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2"); + ok(ret == 2, "expected 2, got %ld\n", ret); + + ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", FALSE); + check_lb_state(listbox, 3, LB_ERR, 0, 0); + + log_all_parent_messages--; + DestroyWindow(listbox); DestroyWindow(parent); } @@ -13983,6 +15051,37 @@ static const struct message NCRBUTTONDOWNSeq[] = { 0 } }; +static const struct message NCXBUTTONUPSeq1[] = +{ + { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) }, + { 0 } +}; + +static const struct message NCXBUTTONUPSeq2[] = +{ + { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) }, + { 0 } +}; + +struct rbuttonup_thread_data +{ + HWND hwnd; + HANDLE wndproc_finished; +}; + +static DWORD CALLBACK post_rbuttonup_msg( void *arg ) +{ + struct rbuttonup_thread_data *data = arg; + DWORD ret; + + ret = WaitForSingleObject( data->wndproc_finished, 500 ); + todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret ); + if( ret == WAIT_OBJECT_0 ) return 0; + + PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 ); + return 0; +} + static void test_defwinproc(void) { HWND hwnd; @@ -13992,12 +15091,32 @@ static void test_defwinproc(void) RECT rect; INT x, y; LRESULT res; + struct rbuttonup_thread_data data; + char buffA[64]; + HANDLE thread; hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc", WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL); assert(hwnd); flush_events(); + buffA[0] = 0; + GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA)); + ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); + + /* Zero high word of the lParam */ + res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234); + ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res); + + GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA)); + ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); + + res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234); + ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res); + + GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA)); + ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA); + GetCursorPos(&pos); GetWindowRect(hwnd, &rect); x = (rect.left+rect.right) / 2; @@ -14007,11 +15126,41 @@ static void test_defwinproc(void) res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y)); ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res); + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + flush_events(); + flush_sequence(); - PostMessageA( hwnd, WM_RBUTTONUP, 0, 0); + mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 ); + /* workaround for missing support for clicking on window frame */ + data.hwnd = hwnd; + data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL ); + thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL ); + DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y)); ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE); + res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y)); + ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE); + + res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y)); + ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE); + + res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y)); + ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE); + + res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y)); + ok(!res, "WM_NCXBUTTONUP returned %ld\n", res); + ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE); + + SetEvent( data.wndproc_finished ); + WaitForSingleObject( thread, 1000 ); + CloseHandle( data.wndproc_finished ); + CloseHandle( thread ); + SetCursorPos(pos.x, pos.y); DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0); @@ -14100,6 +15249,7 @@ static void test_clipboard_viewers(void) trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3); assert(hWnd1 && hWnd2 && hWnd3); + CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */ flush_sequence(); /* Test getting the clipboard viewer and setting the viewer to NULL. */ @@ -15604,8 +16754,8 @@ static void test_layered_window(void) size.cx = 0; ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" ); - ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(ERROR_MR_MID_NOT_FOUND) /* win7 */, - "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) || + broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() ); size.cx = 1; size.cy = -1; ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE ); @@ -15686,6 +16836,7 @@ static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, L static void test_TrackPopupMenu(void) { + MSG msg; HWND hwnd; BOOL ret; @@ -15708,6 +16859,20 @@ static void test_TrackPopupMenu(void) ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE); ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError()); + /* Test popup closing with an ESC-press */ + flush_events(); + PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0); + ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL); + ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError()); + PostQuitMessage(0); + flush_sequence(); + while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) ) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */ + SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc); flush_events(); @@ -15809,8 +16974,8 @@ static DWORD WINAPI SendMessage_thread_2(void *param) PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0); /* this leads to sending an internal message under Wine */ - trace("thread: call EnableWindow\n"); - EnableWindow(wnd_event->hwnd, TRUE); + trace("thread: call SetParent\n"); + SetParent(wnd_event->hwnd, wnd_event->hwnd); trace("thread: call SendMessage\n"); SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0); @@ -16125,6 +17290,8 @@ START_TEST(msg) invisible_parent_tests(); test_mdi_messages(); test_button_messages(); + test_autoradio_BM_CLICK(); + test_autoradio_kbd_move(); test_static_messages(); test_listbox_messages(); test_combobox_messages(); @@ -16425,6 +17592,8 @@ START_TEST(msg_controls) { init_tests(); test_button_messages(); + test_autoradio_BM_CLICK(); + test_autoradio_kbd_move(); test_static_messages(); test_listbox_messages(); test_combobox_messages(); diff --git a/rostests/winetests/user32/resource.rc b/rostests/winetests/user32/resource.rc index a9e45e90ce1..3823ed39e42 100755 --- a/rostests/winetests/user32/resource.rc +++ b/rostests/winetests/user32/resource.rc @@ -75,6 +75,28 @@ FONT 8, "MS Shell Dlg" PUSHBUTTON "Cancel", IDCANCEL,109,20,50,14, WS_TABSTOP | WS_GROUP } +AUTORADIO_TEST_DIALOG_1 DIALOGEX 0, 0, 200, 200 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU | WS_VISIBLE +CAPTION "Radio Button Test Dialog" +FONT 8, "MS Shell Dlg" +{ + CONTROL "Radio1",501,"my_button_class",WS_VISIBLE | WS_CHILD | WS_GROUP | BS_AUTORADIOBUTTON | BS_NOTIFY | WS_TABSTOP,10,10,70,18 + CONTROL "Radio3",503,"my_button_class",WS_VISIBLE | WS_CHILD | BS_RADIOBUTTON | BS_NOTIFY | WS_TABSTOP,10,35,70,18 + CONTROL "Text",504,"my_button_class",WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP,10,60,70,18 + CONTROL "Radio2",502,"my_button_class",WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_NOTIFY | WS_TABSTOP,10,85,70,18 +} + +AUTORADIO_TEST_DIALOG_2 DIALOGEX 0, 0, 200, 200 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU | WS_VISIBLE +CAPTION "Radio Button Test Dialog" +FONT 8, "MS Shell Dlg" +{ + CONTROL "Radio1",501,"my_button_class",WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_NOTIFY | WS_TABSTOP,10,10,70,18 + CONTROL "Radio3",503,"my_button_class",WS_VISIBLE | WS_CHILD | BS_RADIOBUTTON | BS_NOTIFY,10,35,70,18 + CONTROL "Text",504,"my_button_class",WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY,10,60,70,18 + CONTROL "Radio2",502,"my_button_class",WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_NOTIFY,10,85,70,18 +} + CLASS_TEST_DIALOG DIALOG 0, 0, 91, 28 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "CreateDialogParams Test" diff --git a/rostests/winetests/user32/sysparams.c b/rostests/winetests/user32/sysparams.c index 0bf87838edd..350497bd450 100755 --- a/rostests/winetests/user32/sysparams.c +++ b/rostests/winetests/user32/sysparams.c @@ -40,9 +40,12 @@ #endif static LONG (WINAPI *pChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID); +static BOOL (WINAPI *pIsProcessDPIAware)(void); +static BOOL (WINAPI *pSetProcessDPIAware)(void); +static LONG (WINAPI *pGetAutoRotationState)(PAR_STATE); static BOOL strict; -static int dpi; +static int dpi, real_dpi; static BOOL iswin9x; static HDC hdc; @@ -166,6 +169,36 @@ static int last_bpp; static BOOL displaychange_ok = FALSE, displaychange_test_active = FALSE; static HANDLE displaychange_sem = 0; +static BOOL get_reg_dword(HKEY base, const char *key_name, const char *value_name, DWORD *value) +{ + HKEY key; + DWORD type, data, size = sizeof(data); + BOOL ret = FALSE; + + if (RegOpenKeyA(base, key_name, &key) == ERROR_SUCCESS) + { + if (RegQueryValueExA(key, value_name, NULL, &type, (void *)&data, &size) == ERROR_SUCCESS && + type == REG_DWORD) + { + *value = data; + ret = TRUE; + } + RegCloseKey(key); + } + return ret; +} + +static DWORD get_real_dpi(void) +{ + DWORD dpi; + + if (get_reg_dword(HKEY_CURRENT_USER, "Control Panel\\Desktop", "LogPixels", &dpi)) + return dpi; + if (get_reg_dword(HKEY_CURRENT_CONFIG, "Software\\Fonts", "LogPixels", &dpi)) + return dpi; + return USER_DEFAULT_SCREEN_DPI; +} + static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { @@ -872,7 +905,7 @@ static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ static BOOL dotest_spi_iconhorizontalspacing( INT curr_val) { BOOL rc; - INT spacing, regval; + INT spacing, regval, min_val = MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI ); ICONMETRICSA im; rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, curr_val, 0, @@ -880,7 +913,7 @@ static BOOL dotest_spi_iconhorizontalspacing( INT curr_val) if (!test_error_msg(rc,"SPI_ICONHORIZONTALSPACING")) return FALSE; ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); test_change_message( SPI_ICONHORIZONTALSPACING, 0 ); - if( curr_val < 32) curr_val = 32; + curr_val = max( curr_val, min_val ); /* The registry keys depend on the Windows version and the values too * let's test (works on win95,ME,NT4,2k,XP) */ @@ -1041,7 +1074,7 @@ static void test_SPI_SETKEYBOARDDELAY( void ) /* 23 */ static BOOL dotest_spi_iconverticalspacing( INT curr_val) { BOOL rc; - INT spacing, regval; + INT spacing, regval, min_val = MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI ); ICONMETRICSA im; rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, curr_val, 0, @@ -1049,7 +1082,7 @@ static BOOL dotest_spi_iconverticalspacing( INT curr_val) if (!test_error_msg(rc,"SPI_ICONVERTICALSPACING")) return FALSE; ok(rc, "SystemParametersInfoA: rc=%d err=%d\n", rc, GetLastError()); test_change_message( SPI_ICONVERTICALSPACING, 0 ); - if( curr_val < 32) curr_val = 32; + curr_val = max( curr_val, min_val ); /* The registry keys depend on the Windows version and the values too * let's test (works on win95,ME,NT4,2k,XP) */ @@ -1412,7 +1445,7 @@ static void test_SPI_SETDRAGFULLWINDOWS( void ) /* 37 */ #define test_reg_font( KEY, VAL, LF) \ { LOGFONTA lfreg;\ lffromreg( KEY, VAL, &lfreg);\ - ok( (lfreg.lfHeight < 0 ? (LF).lfHeight == lfreg.lfHeight :\ + ok( (lfreg.lfHeight < 0 ? (LF).lfHeight == MulDiv( lfreg.lfHeight, dpi, real_dpi ) : \ MulDiv( -(LF).lfHeight , 72, dpi) == lfreg.lfHeight )&&\ (LF).lfWidth == lfreg.lfWidth &&\ (LF).lfWeight == lfreg.lfWeight &&\ @@ -1476,12 +1509,14 @@ static void test_SPI_SETNONCLIENTMETRICS( void ) /* 44 */ the caption font height is higher than the CaptionHeight field, the latter is adjusted accordingly. To be able to restore these setting accurately be restore the raw values. */ - Ncmorig.iCaptionWidth = metricfromreg( SPI_METRIC_REGKEY, SPI_CAPTIONWIDTH_VALNAME, dpi); + Ncmorig.iCaptionWidth = metricfromreg( SPI_METRIC_REGKEY, SPI_CAPTIONWIDTH_VALNAME, real_dpi); Ncmorig.iCaptionHeight = metricfromreg( SPI_METRIC_REGKEY, SPI_CAPTIONHEIGHT_VALNAME, dpi); Ncmorig.iSmCaptionHeight = metricfromreg( SPI_METRIC_REGKEY, SPI_SMCAPTIONHEIGHT_VALNAME, dpi); Ncmorig.iMenuHeight = metricfromreg( SPI_METRIC_REGKEY, SPI_MENUHEIGHT_VALNAME, dpi); /* test registry entries */ TEST_NONCLIENTMETRICS_REG( Ncmorig) + Ncmorig.lfCaptionFont.lfHeight = MulDiv( Ncmorig.lfCaptionFont.lfHeight, real_dpi, dpi ); + /* make small changes */ Ncmnew = Ncmstart; Ncmnew.iBorderWidth += 1; @@ -2671,7 +2706,7 @@ static void test_GetSystemMetrics( void) HDC hdc = CreateICA( "Display", 0, 0, 0); UINT avcwCaption; - INT CaptionWidthfromreg; + INT CaptionWidthfromreg, smicon, broken_val; MINIMIZEDMETRICS minim; NONCLIENTMETRICSA ncm; SIZE screen; @@ -2738,8 +2773,9 @@ static void test_GetSystemMetrics( void) ok_gsm( SM_CYDLGFRAME, 3); ok_gsm( SM_CYVTHUMB, ncm.iScrollHeight); ok_gsm( SM_CXHTHUMB, ncm.iScrollHeight); - /* SM_CXICON */ - /* SM_CYICON */ + /* These don't depend on the Shell Icon Size registry value */ + ok_gsm( SM_CXICON, MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI ) ); + ok_gsm( SM_CYICON, MulDiv( 32, dpi, USER_DEFAULT_SCREEN_DPI ) ); /* SM_CXCURSOR */ /* SM_CYCURSOR */ ok_gsm( SM_CYMENU, ncm.iMenuHeight + 1); @@ -2784,8 +2820,32 @@ static void test_GetSystemMetrics( void) /* sign-extension for iHorzGap/iVertGap is broken on Win9x */ ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + (short)minim.iHorzGap ); ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + (short)minim.iVertGap ); - /* SM_CXSMICON */ - /* SM_CYSMICON */ + + smicon = MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI ); + if (!pIsProcessDPIAware || pIsProcessDPIAware()) + smicon = max( min( smicon, CaptionWidthfromreg - 2), 4 ) & ~1; + todo_wine_if( real_dpi == dpi && smicon != (MulDiv( 16, dpi, USER_DEFAULT_SCREEN_DPI) & ~1) ) + { + broken_val = (min( ncm.iCaptionHeight, CaptionWidthfromreg ) - 2) & ~1; + broken_val = min( broken_val, 20 ); + + if (smicon == 4) + { + ok_gsm_2( SM_CXSMICON, smicon, 6 ); + ok_gsm_2( SM_CYSMICON, smicon, 6 ); + } + else if (smicon < broken_val) + { + ok_gsm_2( SM_CXSMICON, smicon, broken_val ); + ok_gsm_2( SM_CYSMICON, smicon, broken_val ); + } + else + { + ok_gsm( SM_CXSMICON, smicon ); + ok_gsm( SM_CYSMICON, smicon ); + } + } + ok_gsm( SM_CYSMCAPTION, ncm.iSmCaptionHeight + 1); ok_gsm_3( SM_CXSMSIZE, ncm.iSmCaptionWidth, /* classic/standard windows style */ @@ -2918,6 +2978,48 @@ static void test_GetSysColorBrush(void) win_skip("COLOR_MENUBAR unsupported\n"); } +static void test_dpi_aware(void) +{ + BOOL ret; + + if (!pIsProcessDPIAware) + { + win_skip("IsProcessDPIAware not available\n"); + return; + } + + ret = pSetProcessDPIAware(); + ok(ret, "got %d\n", ret); + + ret = pIsProcessDPIAware(); + ok(ret, "got %d\n", ret); + + dpi = real_dpi; + test_GetSystemMetrics(); +} + +static void test_GetAutoRotationState(void) +{ + AR_STATE state; + BOOL ret; + + if (!pGetAutoRotationState) + { + win_skip("GetAutoRotationState not supported\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pGetAutoRotationState(NULL); + ok(!ret, "Expected GetAutoRotationState to fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + state = 0; + ret = pGetAutoRotationState(&state); + ok(ret, "Expected GetAutoRotationState to succeed, error %d\n", GetLastError()); + ok((state & AR_NOSENSOR) != 0, "Expected AR_NOSENSOR, got %d\n", state); +} + START_TEST(sysparams) { int argc; @@ -2929,11 +3031,16 @@ START_TEST(sysparams) HANDLE hInstance, hdll; hdll = GetModuleHandleA("user32.dll"); - pChangeDisplaySettingsExA=(void*)GetProcAddress(hdll, "ChangeDisplaySettingsExA"); + pChangeDisplaySettingsExA = (void*)GetProcAddress(hdll, "ChangeDisplaySettingsExA"); + pIsProcessDPIAware = (void*)GetProcAddress(hdll, "IsProcessDPIAware"); + pSetProcessDPIAware = (void*)GetProcAddress(hdll, "SetProcessDPIAware"); + pGetAutoRotationState = (void*)GetProcAddress(hdll, "GetAutoRotationState"); hInstance = GetModuleHandleA( NULL ); hdc = GetDC(0); dpi = GetDeviceCaps( hdc, LOGPIXELSY); + real_dpi = get_real_dpi(); + trace("dpi %d real_dpi %d\n", dpi, real_dpi); iswin9x = GetVersion() & 0x80000000; /* This test requires interactivity, if we don't have it, give up */ @@ -2949,6 +3056,7 @@ START_TEST(sysparams) trace("testing EnumDisplaySettings vs GetDeviceCaps\n"); test_EnumDisplaySettings( ); test_GetSysColorBrush( ); + test_GetAutoRotationState( ); change_counter = 0; change_last_param = 0; @@ -2978,4 +3086,5 @@ START_TEST(sysparams) } ReleaseDC( 0, hdc); + test_dpi_aware(); } diff --git a/rostests/winetests/user32/text.c b/rostests/winetests/user32/text.c index bebf6a062f7..3cc95715217 100755 --- a/rostests/winetests/user32/text.c +++ b/rostests/winetests/user32/text.c @@ -26,6 +26,7 @@ #include "wingdi.h" #include "winuser.h" #include "winerror.h" +#include "winnls.h" #define MODIFIED(rect) (rect.left == 10 && rect.right != 100 && rect.top == 10 && rect.bottom != 100) #define EMPTY(rect) (rect.left == rect.right && rect.bottom == rect.top) @@ -746,6 +747,8 @@ static void test_CharToOem_OemToChar(void) }; BOOL ret; int i; + char oem; + WCHAR uni, expect; for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { @@ -807,6 +810,15 @@ static void test_CharToOem_OemToChar(void) ok(ret == tests[i].ret, "test %d: expected %d, got %d\n", i, tests[i].ret, ret); ok(!lstrcmpW(buf, expected), "test %d: got '%s'\n", i, wine_dbgstr_w(buf)); } + + for (i = 0; i < 0x100; i++) + { + oem = i; + ret = OemToCharBuffW( &oem, &uni, 1 ); + ok( ret, "%02x: returns FALSE\n", i ); + MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS, &oem, 1, &expect, 1 ); + ok( uni == expect, "%02x: got %04x expected %04x\n", i, uni, expect ); + } } START_TEST(text) diff --git a/rostests/winetests/user32/uitools.c b/rostests/winetests/user32/uitools.c index 27a41793fdd..b52fe3a03ae 100644 --- a/rostests/winetests/user32/uitools.c +++ b/rostests/winetests/user32/uitools.c @@ -169,7 +169,7 @@ static void test_IsRectEmpty(void) {{-11, -13, -19, -23}, TRUE}, {{11, 13, -17, 19}, TRUE}, {{11, 13, 17, 11}, TRUE}, - /* Non emty rects */ + /* Non empty rects */ {{101, 103, 107, 109}, FALSE}, {{1, -9, 7, 3}, FALSE}, {{-109, -107, -103, -101}, FALSE}, diff --git a/rostests/winetests/user32/wsprintf.c b/rostests/winetests/user32/wsprintf.c index 15e4af0e692..f0e80b2ad65 100755 --- a/rostests/winetests/user32/wsprintf.c +++ b/rostests/winetests/user32/wsprintf.c @@ -119,7 +119,6 @@ static void CharUpperTest(void) for (i=0;i<256;i++) { out = (INT_PTR)CharUpperA((LPSTR)i); - /* printf("%0x ",out); */ if ((out >> 16) != 0) { failed = TRUE; @@ -137,7 +136,6 @@ static void CharLowerTest(void) for (i=0;i<256;i++) { out = (INT_PTR)CharLowerA((LPSTR)i); - /* printf("%0x ",out); */ if ((out >> 16) != 0) { failed = TRUE;