From bca9ea7b61044151804a62738689b8b7e521d45f Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Wed, 7 Sep 2016 23:24:48 +0000 Subject: [PATCH] [USER32_WINETEST] Sync with Wine Staging 1.9.18. One skipped part of clipboard.c is documented in CORE-11953 svn path=/trunk/; revision=72616 --- rostests/winetests/user32/clipboard.c | 1201 ++++++++++++++++++++++++- rostests/winetests/user32/dde.c | 6 - rostests/winetests/user32/dialog.c | 50 + rostests/winetests/user32/edit.c | 153 +++- rostests/winetests/user32/input.c | 8 +- rostests/winetests/user32/menu.c | 6 +- rostests/winetests/user32/msg.c | 142 ++- rostests/winetests/user32/win.c | 193 +++- 8 files changed, 1668 insertions(+), 91 deletions(-) diff --git a/rostests/winetests/user32/clipboard.c b/rostests/winetests/user32/clipboard.c index 873117be3b7..273148e967e 100755 --- a/rostests/winetests/user32/clipboard.c +++ b/rostests/winetests/user32/clipboard.c @@ -18,18 +18,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include #include "wine/test.h" #include "winbase.h" #include "winerror.h" #include "wingdi.h" #include "winuser.h" +#include "winnls.h" #define WM_CLIPBOARDUPDATE 0x031D static BOOL (WINAPI *pAddClipboardFormatListener)(HWND hwnd); +static BOOL (WINAPI *pRemoveClipboardFormatListener)(HWND hwnd); static DWORD (WINAPI *pGetClipboardSequenceNumber)(void); +static const BOOL is_win64 = sizeof(void *) > sizeof(int); static int thread_from_line; +static char *argv0; static DWORD WINAPI open_clipboard_thread(LPVOID arg) { @@ -55,6 +60,14 @@ static DWORD WINAPI open_and_empty_clipboard_thread(LPVOID arg) return 0; } +static DWORD WINAPI open_and_empty_clipboard_win_thread(LPVOID arg) +{ + HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); + ok(OpenClipboard(hwnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line ); + return 0; +} + static DWORD WINAPI set_clipboard_data_thread(LPVOID arg) { HWND hwnd = arg; @@ -64,24 +77,70 @@ static DWORD WINAPI set_clipboard_data_thread(LPVOID arg) if (GetClipboardOwner() == hwnd) { SetClipboardData( CF_WAVE, 0 ); - todo_wine ok( IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData failed\n", thread_from_line ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData failed\n", thread_from_line ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); ok( ret != 0, "%u: SetClipboardData failed err %u\n", thread_from_line, GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = GetClipboardData( CF_WAVE ); + ok( !ret, "%u: GetClipboardData succeeded\n", thread_from_line ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + thread_from_line, GetLastError()); } else { SetClipboardData( CF_WAVE, 0 ); - todo_wine ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", - thread_from_line, GetLastError()); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + thread_from_line, GetLastError()); ok( !IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData succeeded\n", thread_from_line ); ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); - todo_wine ok( !ret, "%u: SetClipboardData succeeded\n", thread_from_line ); - todo_wine ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", - thread_from_line, GetLastError()); + ok( !ret, "%u: SetClipboardData succeeded\n", thread_from_line ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n", + thread_from_line, GetLastError()); } return 0; } +static void set_clipboard_data_process( int arg ) +{ + HANDLE ret; + + 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() ); + } + else + { + SetClipboardData( CF_WAVE, 0 ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "process %u: wrong error %u\n", + arg, GetLastError()); + ok( !IsClipboardFormatAvailable( CF_WAVE ), "process %u: SetClipboardData succeeded\n", arg ); + ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); + ok( !ret, "process %u: SetClipboardData succeeded\n", arg ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "process %u: wrong error %u\n", + arg, GetLastError()); + } +} + +static void grab_clipboard_process( int arg ) +{ + BOOL ret; + + SetLastError( 0xdeadbeef ); + ret = OpenClipboard( 0 ); + ok( ret, "OpenClipboard failed\n" ); + ret = EmptyClipboard(); + ok( ret, "EmptyClipboard failed\n" ); + if (arg) + { + HANDLE ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )); + ok( ret != 0, "process %u: SetClipboardData failed err %u\n", arg, GetLastError() ); + } +} + static void run_thread( LPTHREAD_START_ROUTINE func, void *arg, int line ) { DWORD ret; @@ -104,6 +163,66 @@ static void run_thread( LPTHREAD_START_ROUTINE func, void *arg, int line ) CloseHandle(thread); } +static void run_process( const char *args ) +{ + char cmd[MAX_PATH]; + PROCESS_INFORMATION info; + STARTUPINFOA startup; + + sprintf( cmd, "%s clipboard %s", argv0, args ); + memset( &startup, 0, sizeof(startup) ); + startup.cb = sizeof(startup); + ok( CreateProcessA( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ), + "CreateProcess %s failed\n", cmd ); + + winetest_wait_child_process( info.hProcess ); + CloseHandle( info.hProcess ); + CloseHandle( info.hThread ); +} + +static WNDPROC old_proc; +static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + static int wm_renderallformats; + static int wm_drawclipboard; + static int seqno; + DWORD msg_flags = InSendMessageEx( NULL ); + + if (!seqno) seqno = GetClipboardSequenceNumber(); + + trace( "%p msg %04x\n", hwnd, msg ); + if (!wm_renderallformats) + { + ok( GetClipboardOwner() == hwnd, "%04x: wrong owner %p/%p\n", msg, GetClipboardOwner(), hwnd ); + ok( seqno == GetClipboardSequenceNumber(), "%04x: seqno changed\n", msg ); + } + else + { + ok( !GetClipboardOwner(), "%04x: wrong owner %p\n", msg, GetClipboardOwner() ); + ok( seqno + 1 == GetClipboardSequenceNumber(), "%04x: seqno unchanged\n", msg ); + } + ok( GetClipboardViewer() == hwnd, "%04x: wrong viewer %p/%p\n", msg, GetClipboardViewer(), hwnd ); + ok( GetOpenClipboardWindow() == hwnd, "%04x: wrong open win %p/%p\n", + msg, GetOpenClipboardWindow(), hwnd ); + + switch (msg) + { + 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" ); + break; + case WM_DRAWCLIPBOARD: + ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); + wm_drawclipboard++; + break; + case WM_RENDERALLFORMATS: + ok( msg_flags == ISMEX_NOSEND, "WM_RENDERALLFORMATS wrong flags %x\n", msg_flags ); + wm_renderallformats++; + break; + } + return old_proc( hwnd, msg, wp, lp ); +} + static void test_ClipboardOwner(void) { HWND hWnd1, hWnd2; @@ -139,6 +258,9 @@ static void test_ClipboardOwner(void) run_thread( open_clipboard_thread, hWnd1, __LINE__ ); run_thread( empty_clipboard_thread, 0, __LINE__ ); run_thread( set_clipboard_data_thread, hWnd1, __LINE__ ); + ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" ); + ok( !GetClipboardData( CF_WAVE ), "CF_WAVE data available\n" ); + run_process( "set_clipboard_data 0" ); ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n"); ok(OpenClipboard(hWnd1), "OpenClipboard failed\n"); @@ -154,6 +276,9 @@ static void test_ClipboardOwner(void) ok(GetClipboardOwner() == hWnd1, "clipboard should be owned by %p, not by %p\n", hWnd1, GetClipboardOwner()); run_thread( empty_clipboard_thread, 0, __LINE__ ); run_thread( set_clipboard_data_thread, hWnd1, __LINE__ ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); + ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); + run_process( "set_clipboard_data 1" ); SetLastError(0xdeadbeef); ret = OpenClipboard(hWnd2); @@ -172,6 +297,9 @@ static void test_ClipboardOwner(void) ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner %p/%p\n", GetClipboardOwner(), GetDesktopWindow() ); run_thread( set_clipboard_data_thread, GetDesktopWindow(), __LINE__ ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); + ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); + run_process( "set_clipboard_data 2" ); ret = CloseClipboard(); ok( ret, "CloseClipboard error %d\n", GetLastError()); @@ -179,39 +307,67 @@ static void test_ClipboardOwner(void) ok( ret, "OpenClipboard error %d\n", GetLastError()); ret = EmptyClipboard(); ok( ret, "EmptyClipboard error %d\n", GetLastError()); + SetClipboardData( CF_WAVE, 0 ); + SetClipboardViewer( hWnd1 ); ok( GetClipboardOwner() == hWnd1, "wrong owner %p/%p\n", GetClipboardOwner(), hWnd1 ); - ret = CloseClipboard(); - ok( ret, "CloseClipboard error %d\n", GetLastError()); + ok( GetClipboardViewer() == hWnd1, "wrong viewer %p/%p\n", GetClipboardViewer(), hWnd1 ); + ok( GetOpenClipboardWindow() == hWnd1, "wrong open win %p/%p\n", GetOpenClipboardWindow(), hWnd1 ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); + old_proc = (WNDPROC)SetWindowLongPtrA( hWnd1, GWLP_WNDPROC, (LONG_PTR)winproc_wrapper ); ret = DestroyWindow(hWnd1); ok( ret, "DestroyWindow error %d\n", GetLastError()); ret = DestroyWindow(hWnd2); ok( ret, "DestroyWindow error %d\n", GetLastError()); SetLastError(0xdeadbeef); 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" ); + + SetLastError( 0xdeadbeef ); + ret = CloseClipboard(); + ok( !ret, "CloseClipboard succeeded\n" ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() ); ret = OpenClipboard( 0 ); ok( ret, "OpenClipboard error %d\n", GetLastError()); run_thread( set_clipboard_data_thread, 0, __LINE__ ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); + ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); + run_process( "set_clipboard_data 3" ); ret = CloseClipboard(); ok( ret, "CloseClipboard error %d\n", GetLastError()); run_thread( open_and_empty_clipboard_thread, 0, __LINE__ ); + ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() ); ret = OpenClipboard( 0 ); ok( ret, "OpenClipboard error %d\n", GetLastError()); run_thread( set_clipboard_data_thread, 0, __LINE__ ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); + ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" ); + run_process( "set_clipboard_data 4" ); ret = EmptyClipboard(); ok( ret, "EmptyClipboard error %d\n", GetLastError()); ret = CloseClipboard(); ok( ret, "CloseClipboard error %d\n", GetLastError()); SetLastError( 0xdeadbeef ); - todo_wine ok( !SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )), - "SetClipboardData succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() ); - todo_wine ok( !IsClipboardFormatAvailable( CF_WAVE ), "SetClipboardData succeeded\n" ); + ok( !SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )), + "SetClipboardData succeeded\n" ); + ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() ); + ok( !IsClipboardFormatAvailable( CF_WAVE ), "SetClipboardData succeeded\n" ); + run_thread( open_and_empty_clipboard_thread, GetDesktopWindow(), __LINE__ ); + ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner window %p / %p\n", + GetClipboardOwner(), GetDesktopWindow() ); + + run_thread( open_and_empty_clipboard_win_thread, 0, __LINE__ ); + ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() ); } static void test_RegisterClipboardFormatA(void) @@ -327,7 +483,7 @@ todo_wine ok(format_id == 1234, "invalid clipboard format id %04x\n", format_id); } -static HGLOBAL create_text(void) +static HGLOBAL create_textA(void) { HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5); char *p = GlobalLock(h); @@ -336,6 +492,34 @@ static HGLOBAL create_text(void) 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)); + WCHAR *p = GlobalLock(h); + lstrcpyW(p, testW); + GlobalUnlock(h); + return h; +} + +static HANDLE create_metafile(void) +{ + const RECT rect = {0, 0, 100, 100}; + METAFILEPICT *pict; + HANDLE ret; + HMETAFILE mf; + HDC hdc = CreateMetaFileA( NULL ); + ExtTextOutA( hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL ); + mf = CloseMetaFile( hdc ); + ret = GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(*pict) ); + pict = GlobalLock( ret ); + pict->mm = MM_TEXT; + pict->xExt = pict->yExt = 100; + pict->hMF = mf; + GlobalUnlock( ret ); + return ret; +} + static HENHMETAFILE create_emf(void) { const RECT rect = {0, 0, 100, 100}; @@ -344,15 +528,66 @@ static HENHMETAFILE create_emf(void) return CloseEnhMetaFile(hdc); } +static HBITMAP create_bitmap(void) +{ + HDC hdc = GetDC( 0 ); + UINT bpp = GetDeviceCaps( hdc, BITSPIXEL ); + ReleaseDC( 0, hdc ); + return CreateBitmap( 10, 10, 1, bpp, NULL ); +} + +static HBITMAP create_dib( BOOL v5 ) +{ + HANDLE ret; + BITMAPINFOHEADER *hdr; + + ret = GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, + sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD) + 16 * 16 * 4 ); + hdr = GlobalLock( ret ); + hdr->biSize = v5 ? sizeof(BITMAPV5HEADER) : sizeof(*hdr); + hdr->biWidth = 16; + hdr->biHeight = 16; + hdr->biPlanes = 1; + hdr->biBitCount = 32; + hdr->biCompression = BI_RGB; + if (v5) + { + BITMAPV5HEADER *hdr5 = (BITMAPV5HEADER *)hdr; + hdr5->bV5RedMask = 0x0000ff; + hdr5->bV5GreenMask = 0x00ff00; + hdr5->bV5BlueMask = 0xff0000; + hdr5->bV5AlphaMask = 0xff000000; + } + GlobalUnlock( ret ); + return ret; +} + 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 }, + { 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) }, + }; + HGLOBAL h, htext; HENHMETAFILE emf; BOOL r; - UINT cf; + UINT cf, i, j, count; HANDLE data; - htext = create_text(); + htext = create_textA(); emf = create_emf(); r = OpenClipboard(NULL); @@ -366,6 +601,21 @@ static void test_synthesized(void) r = CloseClipboard(); ok(r, "gle %d\n", GetLastError()); + count = CountClipboardFormats(); + todo_wine 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()); + r = IsClipboardFormatAvailable( CF_OEMTEXT ); + ok( r, "CF_OEMTEXT not available err %d\n", GetLastError()); + r = IsClipboardFormatAvailable( CF_UNICODETEXT ); + ok( r, "CF_UNICODETEXT not available err %d\n", GetLastError()); + r = IsClipboardFormatAvailable( CF_ENHMETAFILE ); + ok( r, "CF_ENHMETAFILE not available err %d\n", GetLastError()); + r = IsClipboardFormatAvailable( CF_METAFILEPICT ); + ok( r, "CF_METAFILEPICT not available err %d\n", GetLastError()); + r = OpenClipboard(NULL); ok(r, "gle %d\n", GetLastError()); cf = EnumClipboardFormats(0); @@ -381,7 +631,11 @@ static void test_synthesized(void) 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_OEMTEXT, "cf %08x\n", cf); data = GetClipboardData(cf); ok(data != NULL, "couldn't get data, cf %08x\n", cf); @@ -402,35 +656,187 @@ static void test_synthesized(void) r = CloseClipboard(); ok(r, "gle %d\n", GetLastError()); + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + r = OpenClipboard(NULL); + ok(r, "%u: gle %d\n", i, GetLastError()); + r = EmptyClipboard(); + ok(r, "%u: gle %d\n", i, GetLastError()); + + switch (tests[i].format) + { + case CF_TEXT: + case CF_OEMTEXT: + SetClipboardData( tests[i].format, create_textA() ); + break; + case CF_UNICODETEXT: + SetClipboardData( CF_UNICODETEXT, create_textW() ); + break; + case CF_ENHMETAFILE: + SetClipboardData( CF_ENHMETAFILE, create_emf() ); + break; + case CF_METAFILEPICT: + SetClipboardData( CF_METAFILEPICT, create_metafile() ); + break; + case CF_BITMAP: + SetClipboardData( CF_BITMAP, create_bitmap() ); + break; + case CF_DIB: + case CF_DIBV5: + SetClipboardData( tests[i].format, create_dib( tests[i].format == CF_DIBV5 )); + break; + } + + count = CountClipboardFormats(); + ok( count == 1, "%u: count %u\n", i, count ); + + r = CloseClipboard(); + ok(r, "%u: gle %d\n", i, GetLastError()); + + 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 ); + + r = OpenClipboard(NULL); + 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; + 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) + { + UINT *ptr = GlobalLock( data ); + ok( GlobalSize( data ) == sizeof(*ptr), "%u: size %lu\n", i, GlobalSize( data )); + ok( *ptr == GetUserDefaultLCID() || + broken( *ptr == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )), + "%u: CF_LOCALE %08x/%08x\n", i, *ptr, GetUserDefaultLCID() ); + GlobalUnlock( data ); + } + } + if (!tests[i].expected[j]) + { + cf = EnumClipboardFormats( cf ); + ok(cf == 0, "%u: cf %04x\n", i, cf); + } + + /* now with delayed rendering */ + + r = EmptyClipboard(); + ok(r, "%u: gle %d\n", i, GetLastError()); + + SetClipboardData( tests[i].format, 0 ); + + count = CountClipboardFormats(); + ok( count == 1, "%u: count %u\n", i, count ); + + r = CloseClipboard(); + ok(r, "%u: gle %d\n", i, GetLastError()); + + 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 ); + + r = OpenClipboard(NULL); + 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; + data = GetClipboardData( cf ); + if (cf == CF_LOCALE) + ok(data != NULL, "%u: CF_LOCALE no data\n", i); + else + ok(!data, "%u: format %04x got data %p\n", i, cf, data); + } + if (!tests[i].expected[j]) + { + cf = EnumClipboardFormats( cf ); + ok(cf == 0, "%u: cf %04x\n", i, cf); + } + r = CloseClipboard(); + ok(r, "%u: gle %d\n", i, GetLastError()); + } + + r = OpenClipboard(NULL); + ok(r, "gle %d\n", GetLastError()); + r = EmptyClipboard(); + ok(r, "gle %d\n", GetLastError()); + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); } static CRITICAL_SECTION clipboard_cs; static HWND next_wnd; +static UINT wm_drawclipboard; +static UINT wm_clipboardupdate; +static UINT wm_destroyclipboard; +static UINT wm_renderformat; +static UINT nb_formats; +static BOOL cross_thread; + static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { - static UINT wm_drawclipboard; - static UINT wm_clipboardupdate; - static UINT wm_destroyclipboard; LRESULT ret; + DWORD msg_flags = InSendMessageEx( NULL ); switch(msg) { case WM_DRAWCLIPBOARD: + ok( msg_flags == (cross_thread ? ISMEX_NOTIFY : ISMEX_NOSEND), + "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); EnterCriticalSection(&clipboard_cs); wm_drawclipboard++; LeaveCriticalSection(&clipboard_cs); break; case WM_CHANGECBCHAIN: + ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND), + "WM_CHANGECBCHAIN wrong flags %x\n", msg_flags ); if (next_wnd == (HWND)wp) next_wnd = (HWND)lp; else if (next_wnd) SendMessageA(next_wnd, msg, wp, lp); break; case WM_DESTROYCLIPBOARD: + ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND), + "WM_DESTROYCLIPBOARD wrong flags %x\n", msg_flags ); wm_destroyclipboard++; ok( GetClipboardOwner() == hwnd, "WM_DESTROYCLIPBOARD owner %p\n", GetClipboardOwner() ); + nb_formats = CountClipboardFormats(); + break; + case WM_RENDERFORMAT: + ok( !wm_renderformat, "multiple WM_RENDERFORMAT %04x / %04lx\n", wm_renderformat, wp ); + wm_renderformat = wp; break; case WM_CLIPBOARDUPDATE: + ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %x\n", msg_flags ); + EnterCriticalSection(&clipboard_cs); wm_clipboardupdate++; + LeaveCriticalSection(&clipboard_cs); break; case WM_USER: ChangeClipboardChain(hwnd, next_wnd); @@ -448,6 +854,12 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA ret = wm_destroyclipboard; wm_destroyclipboard = 0; return ret; + case WM_USER+4: + ret = wm_renderformat; + wm_renderformat = 0; + return ret; + case WM_USER+5: + return nb_formats; } return DefWindowProcA(hwnd, msg, wp, lp); @@ -455,10 +867,14 @@ static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARA static DWORD WINAPI clipboard_thread(void *param) { - HWND win = param; + HWND ret, win = param; BOOL r; + MSG msg; HANDLE handle; - UINT count, old_seq = 0, seq; + UINT count, fmt, formats, old_seq = 0, seq; + + cross_thread = (GetWindowThreadProcessId( win, NULL ) != GetCurrentThreadId()); + trace( "%s-threaded test\n", cross_thread ? "multi" : "single" ); if (pGetClipboardSequenceNumber) old_seq = pGetClipboardSequenceNumber(); @@ -467,10 +883,36 @@ static DWORD WINAPI clipboard_thread(void *param) next_wnd = SetClipboardViewer(win); ok(GetLastError() == 0xdeadbeef, "GetLastError = %d\n", GetLastError()); LeaveCriticalSection(&clipboard_cs); + + SetLastError( 0xdeadbeef ); + ret = SetClipboardViewer( (HWND)0xdead ); + ok( !ret, "SetClipboardViewer succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + r = ChangeClipboardChain( win, (HWND)0xdead ); + ok( !r, "ChangeClipboardChain succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + r = ChangeClipboardChain( (HWND)0xdead, next_wnd ); + ok( !r, "ChangeClipboardChain succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + if (pAddClipboardFormatListener) { r = pAddClipboardFormatListener(win); ok( r, "AddClipboardFormatListener failed err %d\n", GetLastError()); + SetLastError( 0xdeadbeef ); + r = pAddClipboardFormatListener( win ); + ok( !r, "AddClipboardFormatListener succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + r = pAddClipboardFormatListener( (HWND)0xdead ); + ok( !r, "AddClipboardFormatListener succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + r = pAddClipboardFormatListener( GetDesktopWindow() ); + ok( r, "AddClipboardFormatListener failed err %d\n", GetLastError()); + r = pRemoveClipboardFormatListener( GetDesktopWindow() ); + ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError()); } if (pGetClipboardSequenceNumber) @@ -478,10 +920,24 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER + 1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + SetLastError( 0xdeadbeef ); + r = OpenClipboard( (HWND)0xdead ); + ok( !r, "OpenClipboard succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -491,10 +947,19 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); r = EmptyClipboard(); ok(r, "EmptyClipboard failed: %d\n", GetLastError()); @@ -505,12 +970,21 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); count = SendMessageA( win, WM_USER+3, 0, 0 ); ok( !count, "WM_DESTROYCLIPBOARD received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); r = EmptyClipboard(); ok(r, "EmptyClipboard failed: %d\n", GetLastError()); @@ -521,14 +995,25 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); count = SendMessageA( win, WM_USER+3, 0, 0 ); ok( count, "WM_DESTROYCLIPBOARD not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + count = SendMessageA( win, WM_USER+5, 0, 0 ); + ok( !count, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count ); - handle = SetClipboardData( CF_TEXT, create_text() ); + handle = SetClipboardData( CF_TEXT, create_textA() ); ok(handle != 0, "SetClipboardData failed: %d\n", GetLastError()); if (pGetClipboardSequenceNumber) @@ -537,10 +1022,19 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); SetClipboardData( CF_UNICODETEXT, 0 ); @@ -550,10 +1044,19 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); SetClipboardData( CF_UNICODETEXT, 0 ); /* same data again */ @@ -563,10 +1066,23 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + ok( IsClipboardFormatAvailable( CF_TEXT ), "CF_TEXT available\n" ); + ok( IsClipboardFormatAvailable( CF_UNICODETEXT ), "CF_UNICODETEXT available\n" ); + ok( !IsClipboardFormatAvailable( CF_OEMTEXT ), "CF_OEMTEXT available\n" ); EnterCriticalSection(&clipboard_cs); r = CloseClipboard(); @@ -579,10 +1095,19 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received %04x\n", fmt ); r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -592,10 +1117,33 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + ok( IsClipboardFormatAvailable( CF_TEXT ), "CF_TEXT available\n" ); + ok( IsClipboardFormatAvailable( CF_UNICODETEXT ), "CF_UNICODETEXT available\n" ); + ok( IsClipboardFormatAvailable( CF_OEMTEXT ), "CF_OEMTEXT available\n" ); + + ok( GetClipboardOwner() == win, "wrong owner %p\n", GetClipboardOwner()); + handle = GetClipboardData( CF_UNICODETEXT ); + ok( !handle, "got data for CF_UNICODETEXT\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( fmt == CF_UNICODETEXT, "WM_RENDERFORMAT received %04x\n", fmt ); + + handle = GetClipboardData( CF_OEMTEXT ); + ok( !handle, "got data for CF_OEMTEXT\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( fmt == CF_UNICODETEXT, "WM_RENDERFORMAT received %04x\n", fmt ); SetClipboardData( CF_WAVE, 0 ); if (pGetClipboardSequenceNumber) @@ -604,10 +1152,19 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received %04x\n", fmt ); r = CloseClipboard(); ok(r, "CloseClipboard failed: %d\n", GetLastError()); @@ -618,10 +1175,19 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( seq == old_seq, "sequence changed\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received %04x\n", fmt ); r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -633,11 +1199,23 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + count = SendMessageA( win, WM_USER+3, 0, 0 ); + ok( !count, "WM_DESTROYCLIPBOARD received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received %04x\n", fmt ); + formats = CountClipboardFormats(); r = OpenClipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); r = EmptyClipboard(); @@ -645,8 +1223,236 @@ static DWORD WINAPI clipboard_thread(void *param) r = CloseClipboard(); ok(r, "CloseClipboard failed: %d\n", GetLastError()); + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + 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), "WM_CLIPBOARDUPDATE not received\n" ); + count = SendMessageA( win, WM_USER+3, 0, 0 ); + ok( count == 1, "WM_DESTROYCLIPBOARD not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received %04x\n", fmt ); + count = SendMessageA( win, WM_USER+5, 0, 0 ); + ok( count == formats, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count ); + + 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; + } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + count = SendMessageA( win, WM_USER+1, 0, 0 ); + ok( !count, "WM_DRAWCLIPBOARD received\n" ); + count = SendMessageA( win, WM_USER+2, 0, 0 ); + ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + count = SendMessageA( win, WM_USER+3, 0, 0 ); + ok( !count, "WM_DESTROYCLIPBOARD received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received %04x\n", fmt ); + + EnterCriticalSection(&clipboard_cs); + r = CloseClipboard(); + 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; + } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + 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), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + run_process( "grab_clipboard 0" ); + + if (pGetClipboardSequenceNumber) + { + seq = pGetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); + old_seq = seq; + } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + /* in this case we get a cross-thread WM_DRAWCLIPBOARD */ + cross_thread = TRUE; + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + cross_thread = 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), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + 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; + } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + count = SendMessageA( win, WM_USER+1, 0, 0 ); + ok( !count, "WM_DRAWCLIPBOARD received\n" ); + count = SendMessageA( win, WM_USER+2, 0, 0 ); + ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + EnterCriticalSection(&clipboard_cs); + r = CloseClipboard(); + 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; + } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + 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), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + run_process( "grab_clipboard 1" ); + + if (pGetClipboardSequenceNumber) + { + seq = pGetClipboardSequenceNumber(); + ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); + old_seq = seq; + } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + /* in this case we get a cross-thread WM_DRAWCLIPBOARD */ + cross_thread = TRUE; + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + cross_thread = 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), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + 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; + } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + count = SendMessageA( win, WM_USER+1, 0, 0 ); + ok( !count, "WM_DRAWCLIPBOARD received\n" ); + count = SendMessageA( win, WM_USER+2, 0, 0 ); + ok( !count, "WM_CLIPBOARDUPDATE received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + + EnterCriticalSection(&clipboard_cs); + r = CloseClipboard(); + 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; + } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + ok( !wm_renderformat, "WM_RENDERFORMAT received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + 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), "WM_CLIPBOARDUPDATE not received\n" ); + fmt = SendMessageA( win, WM_USER+4, 0, 0 ); + ok( !fmt, "WM_RENDERFORMAT received\n" ); + r = PostMessageA(win, WM_USER, 0, 0); ok(r, "PostMessage failed: %d\n", GetLastError()); + + if (pRemoveClipboardFormatListener) + { + r = pRemoveClipboardFormatListener(win); + ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError()); + SetLastError( 0xdeadbeef ); + r = pRemoveClipboardFormatListener(win); + ok( !r, "RemoveClipboardFormatListener succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + r = pRemoveClipboardFormatListener( (HWND)0xdead ); + ok( !r, "RemoveClipboardFormatListener succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + } return 0; } @@ -672,7 +1478,9 @@ static void test_messages(void) thread = CreateThread(NULL, 0, clipboard_thread, (void*)win, 0, &tid); ok(thread != NULL, "CreateThread failed: %d\n", GetLastError()); - while(GetMessageA(&msg, NULL, 0, 0)) { + while(GetMessageA(&msg, NULL, 0, 0)) + { + ok( msg.message != WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD was posted\n" ); TranslateMessage(&msg); DispatchMessageA(&msg); } @@ -680,19 +1488,358 @@ static void test_messages(void) ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(thread); + DestroyWindow( win ); + + /* same tests again but inside a single thread */ + + win = CreateWindowA( "clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 ); + ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() ); + + clipboard_thread( win ); + DestroyWindow( win ); + UnregisterClassA("clipboard_test", GetModuleHandleA(NULL)); DeleteCriticalSection(&clipboard_cs); } +static BOOL is_moveable( HANDLE handle ) +{ + void *ptr = GlobalLock( handle ); + if (ptr) GlobalUnlock( handle ); + return ptr && ptr != handle; +} + +static BOOL is_fixed( HANDLE handle ) +{ + void *ptr = GlobalLock( handle ); + if (ptr) GlobalUnlock( handle ); + return ptr && ptr == handle; +} + +static BOOL is_freed( HANDLE handle ) +{ + void *ptr = GlobalLock( handle ); + if (ptr) GlobalUnlock( handle ); + return !ptr; +} + +static UINT format_id; +static HBITMAP bitmap, bitmap2; +static HPALETTE palette; +static HPEN pen; +static const LOGPALETTE logpalette = { 0x300, 1 }; + +static void test_handles( HWND hwnd ) +{ + HGLOBAL h, htext, htext2; + BOOL r; + HANDLE data; + DWORD process; + BOOL is_owner = (GetWindowThreadProcessId( hwnd, &process ) && process == GetCurrentProcessId()); + + trace( "hwnd %p\n", hwnd ); + htext = create_textA(); + htext2 = 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 ); + + r = OpenClipboard( hwnd ); + ok( r, "gle %d\n", GetLastError() ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + h = SetClipboardData( CF_TEXT, htext ); + ok( h == htext, "got %p\n", h ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = SetClipboardData( format_id, htext2 ); + ok( h == htext2, "got %p\n", h ); + ok( is_moveable( h ), "expected moveable mem %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 ); + 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 + 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 ); + } + + data = GetClipboardData( CF_TEXT ); + ok( data == htext, "wrong data %p\n", data ); + ok( is_moveable( data ), "expected moveable mem %p\n", data ); + + data = GetClipboardData( format_id ); + ok( data == htext2, "wrong data %p, cf %08x\n", data, format_id ); + ok( is_moveable( data ), "expected moveable mem %p\n", data ); + + 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( 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 ); + + r = OpenClipboard( hwnd ); + ok( r, "gle %d\n", GetLastError() ); + + /* 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 ); + + data = GetClipboardData( CF_TEXT ); + todo_wine 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 ); + } + else + { + ok( is_moveable( htext ), "expected moveable mem %p\n", htext ); + ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext ); + + 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_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_BITMAP ); + ok( data == bitmap, "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( 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 ); + + 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( !GetObjectType( bitmap ), "expected freed handle %p\n", bitmap ); + 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() ); +} + +static DWORD WINAPI test_handles_thread( void *arg ) +{ + trace( "running from different thread\n" ); + test_handles( (HWND)arg ); + return 0; +} + +static DWORD WINAPI test_handles_thread2( void *arg ) +{ + BOOL r; + HANDLE h; + char *ptr; + + r = OpenClipboard( 0 ); + ok( r, "gle %d\n", GetLastError() ); + h = GetClipboardData( CF_TEXT ); + 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 ); + h = GetClipboardData( format_id ); + 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 ); + 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_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 ); + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + return 0; +} + +static void test_handles_process( const char *str ) +{ + BOOL r; + HANDLE h; + char *ptr; + + 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 ); + ptr = GlobalLock( h ); + if (ptr) todo_wine 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 ); + ptr = GlobalLock( h ); + if (ptr) ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr ); + GlobalUnlock( h ); + h = GetClipboardData( CF_BITMAP ); + todo_wine ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h ); + 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 ); + 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_DIB ); + todo_wine 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 ); + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); +} + +static void test_data_handles(void) +{ + BOOL r; + HANDLE h; + HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); + + ok( hwnd != 0, "window creation failed\n" ); + format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" ); + test_handles( 0 ); + test_handles( GetDesktopWindow() ); +#ifndef __REACTOS__ /* CORE-11953 */ + test_handles( hwnd ); +#endif + run_thread( test_handles_thread, hwnd, __LINE__ ); + + bitmap = CreateBitmap( 10, 10, 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() ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + h = SetClipboardData( CF_TEXT, create_textA() ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = SetClipboardData( format_id, create_textA() ); + 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_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 ); + } + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + run_thread( test_handles_thread2, 0, __LINE__ ); + run_process( "handles test" ); + + r = OpenClipboard( hwnd ); + ok( r, "gle %d\n", GetLastError() ); + h = GetClipboardData( CF_TEXT ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + h = GetClipboardData( format_id ); + ok( is_moveable( h ), "expected moveable mem %p\n", h ); + r = EmptyClipboard(); + ok( r, "gle %d\n", GetLastError() ); + r = CloseClipboard(); + ok( r, "gle %d\n", GetLastError() ); + + DestroyWindow( hwnd ); +} + START_TEST(clipboard) { + char **argv; + int argc = winetest_get_mainargs( &argv ); HMODULE mod = GetModuleHandleA( "user32" ); + argv0 = argv[0]; pAddClipboardFormatListener = (void *)GetProcAddress( mod, "AddClipboardFormatListener" ); + pRemoveClipboardFormatListener = (void *)GetProcAddress( mod, "RemoveClipboardFormatListener" ); pGetClipboardSequenceNumber = (void *)GetProcAddress( mod, "GetClipboardSequenceNumber" ); + if (argc == 4 && !strcmp( argv[2], "set_clipboard_data" )) + { + set_clipboard_data_process( atoi( argv[3] )); + return; + } + if (argc == 4 && !strcmp( argv[2], "grab_clipboard" )) + { + grab_clipboard_process( atoi( argv[3] )); + return; + } + if (argc == 4 && !strcmp( argv[2], "handles" )) + { + test_handles_process( argv[3] ); + return; + } + test_RegisterClipboardFormatA(); test_ClipboardOwner(); test_synthesized(); test_messages(); + test_data_handles(); } diff --git a/rostests/winetests/user32/dde.c b/rostests/winetests/user32/dde.c index c90bac92cb6..d63a0f65aa2 100755 --- a/rostests/winetests/user32/dde.c +++ b/rostests/winetests/user32/dde.c @@ -2511,12 +2511,6 @@ static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV ok(!lstrcmpW((WCHAR*)buffer, cmd_w), "Expected %s, msg_index=%d\n", wine_dbgstr_w(cmd_w), msg_index); } - else if (unicode_client) - { - ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n", size, size_w_to_a, msg_index); - ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", - test_cmd_w_to_a, buffer, msg_index); - } else { ok(size == size_w_to_a, "Wrong size %d/%d, msg_index=%d\n", diff --git a/rostests/winetests/user32/dialog.c b/rostests/winetests/user32/dialog.c index b837c8c7e96..a639baa1c58 100755 --- a/rostests/winetests/user32/dialog.c +++ b/rostests/winetests/user32/dialog.c @@ -733,8 +733,23 @@ static void test_WM_NEXTDLGCTL(void) DestroyWindow(g_hwndTestDlg); } +static LRESULT CALLBACK hook_proc(INT code, WPARAM wParam, LPARAM lParam) +{ + ok(0, "unexpected hook called, code %d\n", code); + return CallNextHookEx(NULL, code, wParam, lParam); +} + +static BOOL g_MSGF_DIALOGBOX; +static LRESULT CALLBACK hook_proc2(INT code, WPARAM wParam, LPARAM lParam) +{ + ok(code == MSGF_DIALOGBOX, "unexpected hook called, code %d\n", code); + g_MSGF_DIALOGBOX = code == MSGF_DIALOGBOX; + return CallNextHookEx(NULL, code, wParam, lParam); +} + static void test_IsDialogMessage(void) { + HHOOK hook; MSG msg; g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass", @@ -746,11 +761,34 @@ static void test_IsDialogMessage(void) assert (g_hwndButton1); assert (g_hwndButtonCancel); + if (0) + { + /* crashes on Windows */ + IsDialogMessageA(NULL, NULL); + IsDialogMessageA(g_hwndMain, NULL); + } + /* The focus should initially be nowhere. The first TAB should take it * to the first button. The second TAB should take it to the Cancel * button. */ + + /* valid window, invalid message window */ + hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc2, NULL, GetCurrentThreadId()); + FormTabMsg (&msg, (HWND)0xbeefbeef); + ok (!IsDialogMessageA(g_hwndMain, &msg), "expected failure\n"); + ok(g_MSGF_DIALOGBOX, "hook wasn't called\n"); + g_MSGF_DIALOGBOX = FALSE; + UnhookWindowsHookEx(hook); + + hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId()); FormTabMsg (&msg, g_hwndMain); + + ok (!IsDialogMessageA(NULL, &msg), "expected failure\n"); + ok (!IsDialogMessageA((HWND)0xbeefbeef, &msg), "expected failure\n"); + + UnhookWindowsHookEx(hook); + ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle first TAB\n"); ok ((GetFocus() == g_hwndButton1), "Focus did not move to first button\n"); FormTabMsg (&msg, g_hwndButton1); @@ -760,6 +798,18 @@ static void test_IsDialogMessage(void) FormEnterMsg (&msg, g_hwndButtonCancel); ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n"); ok (g_terminated, "ENTER did not terminate\n"); + + /* matching but invalid window handles, NULL */ + hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId()); + + FormTabMsg (&msg, NULL); + ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n"); + + /* matching but invalid window handles, not NULL */ + FormTabMsg (&msg, (HWND)0xbeefbeef); + ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n"); + + UnhookWindowsHookEx(hook); } diff --git a/rostests/winetests/user32/edit.c b/rostests/winetests/user32/edit.c index e725590aedd..b9aa1c9b952 100755 --- a/rostests/winetests/user32/edit.c +++ b/rostests/winetests/user32/edit.c @@ -1421,14 +1421,118 @@ static void test_edit_control_scroll(void) DestroyWindow (hwEdit); } +static void test_margins_usefontinfo(UINT charset) +{ + HWND hwnd; + HDC hdc; + SIZE size; + BOOL cjk = FALSE; + LOGFONTA lf; + HFONT hfont; + RECT rect; + INT margins, threshold, expect, empty_expect, small_expect; + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -11; + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = charset; + strcpy(lf.lfFaceName, "Tahoma"); + + hfont = CreateFontIndirectA(&lf); + ok(hfont != NULL, "got %p\n", hfont); + + /* Big window rectangle */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 5000, 1000, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + hdc = GetDC(hwnd); + hfont = SelectObject(hdc, hfont); + size.cx = GdiGetCharDimensions( hdc, NULL, &size.cy ); + expect = MAKELONG(size.cx / 2, size.cx / 2); + small_expect = 0; + empty_expect = size.cx >= 28 ? small_expect : expect; + + charset = GetTextCharset(hdc); + switch (charset) + { + case SHIFTJIS_CHARSET: + case HANGUL_CHARSET: + case GB2312_CHARSET: + case CHINESEBIG5_CHARSET: + cjk = TRUE; + } + + hfont = SelectObject(hdc, hfont); + ReleaseDC(hwnd, hdc); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + if (!cjk) + ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + else + { + ok(HIWORD(margins) > 0 && LOWORD(margins) > 0, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + expect = empty_expect = small_expect = margins; + } + DestroyWindow(hwnd); + + threshold = (size.cx / 2 + size.cx) * 2; + + /* Size below which non-cjk margins are zero */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold - 1, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == small_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* Size at which non-cjk margins become non-zero */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, threshold, 100, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(!IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + /* Empty rect */ + hwnd = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + GetClientRect(hwnd, &rect); + ok(IsRectEmpty(&rect), "got rect %s\n", wine_dbgstr_rect(&rect)); + + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == 0, "got %x\n", margins); + + SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); + margins = SendMessageA(hwnd, EM_GETMARGINS, 0, 0); + ok(margins == empty_expect, "%d: got %d, %d\n", charset, HIWORD(margins), LOWORD(margins)); + DestroyWindow(hwnd); + + DeleteObject(hfont); +} + static void test_margins(void) { HWND hwEdit; RECT old_rect, new_rect; INT old_right_margin; DWORD old_margins, new_margins; - LOGFONTA lf; - HFONT hfont; hwEdit = create_editcontrol(WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); @@ -1487,45 +1591,16 @@ static void test_margins(void) DestroyWindow (hwEdit); - memset(&lf, 0, sizeof(lf)); - lf.lfHeight = -11; - lf.lfWeight = FW_NORMAL; - lf.lfCharSet = DEFAULT_CHARSET; - strcpy(lf.lfFaceName, "Tahoma"); + test_margins_usefontinfo(ANSI_CHARSET); + test_margins_usefontinfo(EASTEUROPE_CHARSET); - hfont = CreateFontIndirectA(&lf); - ok(hfont != NULL, "got %p\n", hfont); + test_margins_usefontinfo(SHIFTJIS_CHARSET); + test_margins_usefontinfo(HANGUL_CHARSET); + test_margins_usefontinfo(CHINESEBIG5_CHARSET); + /* Don't test JOHAB_CHARSET. Treated as CJK by Win 8, + but not by < Win 8 and Win 10. */ - /* Empty window rectangle */ - hwEdit = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); - ok(hwEdit != NULL, "got %p\n", hwEdit); - GetClientRect(hwEdit, &old_rect); - ok(IsRectEmpty(&old_rect), "got rect %s\n", wine_dbgstr_rect(&old_rect)); - - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(old_margins == 0, "got %x\n", old_margins); - - SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(HIWORD(old_margins) > 0 && LOWORD(old_margins) > 0, "got %d, %d\n", HIWORD(old_margins), LOWORD(old_margins)); - - DestroyWindow(hwEdit); - - /* Size is not enough to display a text, but not empty */ - hwEdit = CreateWindowExA(0, "Edit", "A", WS_POPUP, 0, 0, 2, 2, NULL, NULL, NULL, NULL); - ok(hwEdit != NULL, "got %p\n", hwEdit); - GetClientRect(hwEdit, &old_rect); - ok(!IsRectEmpty(&old_rect), "got rect %s\n", wine_dbgstr_rect(&old_rect)); - - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(old_margins == 0, "got %x\n", old_margins); - - SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); - old_margins = SendMessageA(hwEdit, EM_GETMARGINS, 0, 0); - ok(old_margins == 0, "got %d, %d\n", HIWORD(old_margins), LOWORD(old_margins)); - - DeleteObject(hfont); - DestroyWindow(hwEdit); + test_margins_usefontinfo(DEFAULT_CHARSET); } static INT CALLBACK find_font_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lParam) diff --git a/rostests/winetests/user32/input.c b/rostests/winetests/user32/input.c index 7744de2945d..41d93e1213f 100755 --- a/rostests/winetests/user32/input.c +++ b/rostests/winetests/user32/input.c @@ -184,7 +184,7 @@ static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) if( TrackSysKey == VK_MENU || /* -down/-up sequence */ (VKey != VK_MENU)) /* -down...-up */ message = WM_SYSKEYUP; - TrackSysKey = 0; /* FIXME */ + TrackSysKey = 0; } InputKeyStateTable[VKey] &= ~0x80; flags |= KF_REPEAT | KF_UP; @@ -1767,10 +1767,8 @@ static void test_keyboard_layout_name(void) BOOL ret; char klid[KL_NAMELENGTH]; -if (0) /* crashes on native system */ -{ - ret = GetKeyboardLayoutNameA(NULL); -} + if (0) /* crashes on native system */ + ret = GetKeyboardLayoutNameA(NULL); SetLastError(0xdeadbeef); ret = GetKeyboardLayoutNameW(NULL); diff --git a/rostests/winetests/user32/menu.c b/rostests/winetests/user32/menu.c index 4735d923c8a..90d1e443403 100755 --- a/rostests/winetests/user32/menu.c +++ b/rostests/winetests/user32/menu.c @@ -3972,15 +3972,13 @@ static void test_AppendMenu(void) mii.wID = 206; ret = InsertMenuItemA(hmenu, 0, TRUE, &mii); ok(ret, "InsertMenuItem failed\n"); -if (0) /* FIXME: uncomment once Wine is fixed */ -{ +if (0) /* FIXME: uncomment once Wine is fixed */ { check_menu_items(hmenu, 206, MF_SEPARATOR, MFS_GRAYED); } mii.wID = 207; ret = SetMenuItemInfoA(hmenu, 0, TRUE, &mii); ok(ret, "SetMenuItemInfo failed\n"); -if (0) /* FIXME: uncomment once Wine is fixed */ -{ +if (0) /* FIXME: uncomment once Wine is fixed */ { check_menu_items(hmenu, 207, MF_SEPARATOR, MFS_GRAYED); } DestroyMenu(hmenu); diff --git a/rostests/winetests/user32/msg.c b/rostests/winetests/user32/msg.c index 3c132846009..6f0dd17920b 100755 --- a/rostests/winetests/user32/msg.c +++ b/rostests/winetests/user32/msg.c @@ -8252,6 +8252,12 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, return 0; } + if (message == WM_CONTEXTMENU) + { + /* don't create context menu */ + return 0; + } + defwndproc_counter++; ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam) : DefWindowProcA(hwnd, message, wParam, lParam); @@ -13968,13 +13974,46 @@ static void test_paintingloop(void) DestroyWindow(hwnd); } +static const struct message NCRBUTTONDOWNSeq[] = +{ + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 }, + { WM_CAPTURECHANGED, sent }, + { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 }, + { 0 } +}; + static void test_defwinproc(void) { HWND hwnd; MSG msg; BOOL gotwmquit = FALSE; - hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL); + POINT pos; + RECT rect; + INT x, y; + LRESULT res; + + hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc", + WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL); assert(hwnd); + flush_events(); + + GetCursorPos(&pos); + GetWindowRect(hwnd, &rect); + x = (rect.left+rect.right) / 2; + y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1; + SetCursorPos(x, y); + flush_events(); + res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y)); + ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res); + + flush_sequence(); + PostMessageA( hwnd, WM_RBUTTONUP, 0, 0); + DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y)); + ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE); + + SetCursorPos(pos.x, pos.y); + DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0); while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) { if( msg.message == WM_QUIT) gotwmquit = TRUE; @@ -14108,7 +14147,7 @@ static void test_clipboard_viewers(void) expect_HWND(hWnd1, GetClipboardViewer()); ChangeClipboardChain(NULL, hWnd2); - ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE); + ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE); expect_HWND(hWnd1, GetClipboardViewer()); /* Actually change clipboard viewer with ChangeClipboardChain. */ @@ -15868,6 +15907,98 @@ todo_wine_if (thread_n == 2) flush_sequence(); } +static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + DWORD flags = InSendMessageEx( NULL ); + BOOL ret; + + switch (msg) + { + case WM_USER: + ok( flags == ISMEX_SEND, "wrong flags %x\n", flags ); + ok( InSendMessage(), "InSendMessage returned false\n" ); + ret = ReplyMessage( msg ); + ok( ret, "ReplyMessage failed err %u\n", GetLastError() ); + flags = InSendMessageEx( NULL ); + ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags ); + ok( InSendMessage(), "InSendMessage returned false\n" ); + break; + case WM_USER + 1: + ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags ); + ok( InSendMessage(), "InSendMessage returned false\n" ); + ret = ReplyMessage( msg ); + ok( ret, "ReplyMessage failed err %u\n", GetLastError() ); + flags = InSendMessageEx( NULL ); + ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags ); + ok( InSendMessage(), "InSendMessage returned false\n" ); + break; + case WM_USER + 2: + ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags ); + ok( InSendMessage(), "InSendMessage returned false\n" ); + ret = ReplyMessage( msg ); + ok( ret, "ReplyMessage failed err %u\n", GetLastError() ); + flags = InSendMessageEx( NULL ); + ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags ); + ok( InSendMessage(), "InSendMessage returned false\n" ); + break; + case WM_USER + 3: + ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags ); + ok( !InSendMessage(), "InSendMessage returned true\n" ); + ret = ReplyMessage( msg ); + ok( !ret, "ReplyMessage succeeded\n" ); + break; + } + + return DefWindowProcA( hwnd, msg, wp, lp ); +} + +static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result ) +{ + ok( msg == WM_USER + 2, "wrong msg %x\n", msg ); + ok( result == WM_USER + 2, "wrong result %lx\n", result ); +} + +static DWORD WINAPI send_message_thread( void *arg ) +{ + HWND win = arg; + + SendMessageA( win, WM_USER, 0, 0 ); + SendNotifyMessageA( win, WM_USER + 1, 0, 0 ); + SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 ); + PostMessageA( win, WM_USER + 3, 0, 0 ); + PostMessageA( win, WM_QUIT, 0, 0 ); + return 0; +} + +static void test_InSendMessage(void) +{ + WNDCLASSA cls; + HWND win; + MSG msg; + HANDLE thread; + DWORD tid; + + memset(&cls, 0, sizeof(cls)); + cls.lpfnWndProc = insendmessage_wnd_proc; + cls.hInstance = GetModuleHandleA(NULL); + cls.lpszClassName = "InSendMessage_test"; + RegisterClassA(&cls); + + win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 ); + ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() ); + + thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid ); + ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() ); + + while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg ); + + ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + CloseHandle( thread ); + + DestroyWindow( win ); + UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) ); +} + static const struct message DoubleSetCaptureSeq[] = { { WM_CAPTURECHANGED, sent }, @@ -15977,6 +16108,7 @@ START_TEST(msg) test_SendMessage_other_thread(1); test_SendMessage_other_thread(2); + test_InSendMessage(); test_SetFocus(); test_SetParent(); test_PostMessage(); @@ -16036,13 +16168,8 @@ START_TEST(msg) test_keyflags(); test_hotkey(); test_layered_window(); - if(!winetest_interactive) - skip("CORE-8299 : Skip Tracking popup menu tests.\n"); - else - { test_TrackPopupMenu(); test_TrackPopupMenuEmpty(); - } test_DoubleSetCapture(); /* keep it the last test, under Windows it tends to break the tests * which rely on active/foreground windows being correct. @@ -16125,6 +16252,7 @@ START_TEST(msg_queue) init_tests(); test_SendMessage_other_thread(1); test_SendMessage_other_thread(2); + test_InSendMessage(); test_PostMessage(); test_broadcast(); test_PeekMessage(); diff --git a/rostests/winetests/user32/win.c b/rostests/winetests/user32/win.c index 8cabb90d908..d1747c97a7d 100644 --- a/rostests/winetests/user32/win.c +++ b/rostests/winetests/user32/win.c @@ -1381,6 +1381,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0}; static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0}; BOOL isWin9x = FALSE; + HMENU frame_menu = GetMenu(parent); + + ok(frame_menu != NULL, "Frame window didn't have a menu\n"); mdi_cs.szClass = "MDI_child_Class_1"; mdi_cs.szTitle = "MDI child"; @@ -1424,6 +1427,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1449,6 +1453,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1465,6 +1470,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1479,6 +1485,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1499,6 +1506,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1525,6 +1533,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1541,6 +1550,26 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); + SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); + ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); + + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child", + WS_MAXIMIZE, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandleA(NULL), + mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); + hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); + exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; + ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); + else + ok(GetMenuItemCount(frame_menu) == 4, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1555,6 +1584,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1575,6 +1605,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1601,6 +1632,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0; ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1626,6 +1658,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(mdi_child != 0, "MDI child creation failed\n"); id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == 0, "wrong child id %ld\n", id); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); DestroyWindow(mdi_child); @@ -1641,6 +1674,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == 0, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); DestroyWindow(mdi_child); /* maximized child */ @@ -1655,6 +1689,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == 0, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); DestroyWindow(mdi_child); trace("Creating maximized child with a caption\n"); @@ -1669,6 +1704,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == 0, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); DestroyWindow(mdi_child); trace("Creating maximized child with a caption and a thick frame\n"); @@ -1683,6 +1719,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) ok(id == 0, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); + ok(GetMenuItemCount(frame_menu) == 0, "Got wrong frame menu item count: %u\n", GetMenuItemCount(frame_menu)); DestroyWindow(mdi_child); } @@ -1796,7 +1833,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L ok(cs->hInstance == mdi_cs->hOwner, "%p != %p\n", cs->hInstance, mdi_cs->hOwner); /* MDICREATESTRUCT should have original values */ - ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff, + ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff || mdi_cs->style == WS_MAXIMIZE, "mdi_cs->style does not match (%08x)\n", mdi_cs->style); ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x); ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y); @@ -2073,11 +2110,12 @@ static BOOL mdi_RegisterWindowClasses(void) static void test_mdi(void) { static const DWORD style[] = { 0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL | WS_VSCROLL }; - HWND mdi_hwndMain, mdi_client; + HWND mdi_hwndMain, mdi_client, mdi_child; CLIENTCREATESTRUCT client_cs; RECT rc; DWORD i; MSG msg; + HMENU frame_menu, child_menu; if (!mdi_RegisterWindowClasses()) assert(0); @@ -2089,6 +2127,8 @@ static void test_mdi(void) GetModuleHandleA(NULL), NULL); assert(mdi_hwndMain); + frame_menu = CreateMenu(); + GetClientRect(mdi_hwndMain, &rc); client_cs.hWindowMenu = 0; @@ -2096,7 +2136,6 @@ static void test_mdi(void) for (i = 0; i < sizeof(style)/sizeof(style[0]); i++) { - HWND mdi_child; SCROLLINFO si; BOOL ret, gotit; @@ -2114,6 +2153,25 @@ static void test_mdi(void) mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); + SendMessageW(mdi_child, WM_SIZE, SIZE_MAXIMIZED, 0); + SetMenu(mdi_hwndMain, frame_menu); + + ok(GetMenuItemCount(frame_menu) == 0, "Frame menu should be empty after child maximize, but has %u\n", + GetMenuItemCount(frame_menu)); + + child_menu = CreateMenu(); + SendMessageW(mdi_client, WM_MDISETMENU, 0, (LPARAM)child_menu); + + ok(GetMenuItemCount(frame_menu) == 0, "Frame menu should be empty after WM_MDISETMENU, but has %u\n", + GetMenuItemCount(frame_menu)); + + SendMessageW(mdi_child, WM_SIZE, SIZE_RESTORED, 0); + + ok(GetMenuItemCount(frame_menu) == 0, "Frame menu should be empty after child restored, but has %u items\n", + GetMenuItemCount(frame_menu)); + + SetMenu(mdi_hwndMain, NULL); + si.cbSize = sizeof(si); si.fMask = SIF_ALL; ret = GetScrollInfo(mdi_client, SB_HORZ, &si); @@ -2222,10 +2280,46 @@ todo_wine else ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]); + DestroyMenu(child_menu); DestroyWindow(mdi_child); DestroyWindow(mdi_client); } + SetMenu(mdi_hwndMain, frame_menu); + + mdi_client = CreateWindowExA(0, "mdiclient", NULL, + WS_CHILD, + 0, 0, rc.right, rc.bottom, + mdi_hwndMain, 0, 0, &client_cs); + ok(mdi_client != 0, "MDI client creation failed\n"); + + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child", + 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, 0, + mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); + + SendMessageW(mdi_child, WM_SIZE, SIZE_MAXIMIZED, 0); + ok(GetMenuItemCount(frame_menu) == 4, "Frame menu should have 4 items after child maximize, but has %u\n", + GetMenuItemCount(frame_menu)); + + child_menu = CreateMenu(); + SendMessageW(mdi_client, WM_MDISETMENU, 0, (LPARAM)child_menu); + + ok(GetMenuItemCount(frame_menu) == 4, "Frame menu should have 4 items after WM_MDISETMENU, but has %u\n", + GetMenuItemCount(frame_menu)); + + SendMessageW(mdi_child, WM_SIZE, SIZE_RESTORED, 0); + + ok(GetMenuItemCount(frame_menu) == 0, "Frame menu should be empty after child restored, but has %u items\n", + GetMenuItemCount(frame_menu)); + + DestroyMenu(child_menu); + DestroyWindow(mdi_child); + DestroyWindow(mdi_client); + /* MDIClient without MDIS_ALLCHILDSTYLES */ mdi_client = CreateWindowExA(0, "mdiclient", NULL, @@ -6258,6 +6352,98 @@ static void test_SetWindowLong(void) } } +static LRESULT WINAPI check_style_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + const STYLESTRUCT *expected = (STYLESTRUCT *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + const STYLESTRUCT *got = (STYLESTRUCT *)lParam; + + if (message == WM_STYLECHANGING && wParam == GWL_STYLE) + { + ok(got->styleOld == expected[0].styleOld, "expected old style %#x, got %#x\n", + expected[0].styleOld, got->styleOld); + ok(got->styleNew == expected[0].styleNew, "expected new style %#x, got %#x\n", + expected[0].styleNew, got->styleNew); + } + else if (message == WM_STYLECHANGED && wParam == GWL_STYLE) + { + ok(got->styleOld == expected[1].styleOld, "expected old style %#x, got %#x\n", + expected[1].styleOld, got->styleOld); + ok(got->styleNew == expected[1].styleNew, "expected new style %#x, got %#x\n", + expected[1].styleNew, got->styleNew); + } + + return DefWindowProcA(hwnd, message, wParam, lParam); +} + +static void test_set_window_style(void) +{ + LONG expected_style, new_style, old_style; + STYLESTRUCT expected_stylestruct[2]; + unsigned int i; + WNDCLASSA cls; + HWND hwnd; + + static const struct + { + LONG creation_style; + LONG style; + } + tests[] = + { + { WS_MINIMIZE | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX }, + { WS_MINIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, + WS_CLIPSIBLINGS | WS_CAPTION }, + { WS_MAXIMIZE | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX }, + { WS_MAXIMIZE | WS_CLIPSIBLINGS | WS_CAPTION, + WS_CLIPSIBLINGS | WS_CAPTION }, + { WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + WS_MINIMIZE | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX }, + { WS_CLIPSIBLINGS | WS_CAPTION, + WS_MINIMIZE | WS_CLIPSIBLINGS | WS_CAPTION }, + { WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + WS_MAXIMIZE | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX }, + { WS_CLIPSIBLINGS | WS_CAPTION, + WS_MAXIMIZE | WS_CLIPSIBLINGS | WS_CAPTION }, + }; + + memset(&cls, 0, sizeof(cls)); + cls.lpfnWndProc = check_style_wnd_proc; + cls.hInstance = GetModuleHandleA(0); + cls.lpszClassName = "TestSetWindowStylesClass"; + ok(RegisterClassA(&cls), "RegisterClass failed\n"); + + for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) + { + expected_style = tests[i].style; + if (tests[i].creation_style & WS_MINIMIZE) + expected_style |= WS_MINIMIZE; + + expected_stylestruct[0].styleOld = tests[i].creation_style; + expected_stylestruct[0].styleNew = tests[i].style; + expected_stylestruct[1].styleOld = tests[i].creation_style; + expected_stylestruct[1].styleNew = expected_style; + + hwnd = CreateWindowA(cls.lpszClassName, "Test set styles", + tests[i].creation_style, 100, 100, 200, 200, 0, 0, 0, NULL); + ok(hwnd != 0, "CreateWindow failed\n"); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)&expected_stylestruct); + + old_style = SetWindowLongA(hwnd, GWL_STYLE, tests[i].style); + ok(old_style == tests[i].creation_style, "expected old style %#x, got %#x\n", + tests[i].creation_style, old_style); + new_style = GetWindowLongA(hwnd, GWL_STYLE); + ok(new_style == expected_style, "expected new style %#x, got %#x\n", + expected_style, new_style); + + SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0); + DestroyWindow(hwnd); + } + + UnregisterClassA(cls.lpszClassName, cls.hInstance); +} + static void test_ShowWindow(void) { HWND hwnd; @@ -9348,6 +9534,7 @@ START_TEST(win) test_redrawnow(); test_csparentdc(); test_SetWindowLong(); + test_set_window_style(); test_ShowWindow(); test_gettext(); test_GetUpdateRect();