[USER32_WINETEST] Sync with Wine Staging 2.9 except win.c. CORE-13362
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 14:34:15 +0000 (14:34 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 14:34:15 +0000 (14:34 +0000)
svn path=/trunk/; revision=74909

15 files changed:
rostests/winetests/user32/class.c
rostests/winetests/user32/clipboard.c
rostests/winetests/user32/combo.c
rostests/winetests/user32/cursoricon.c
rostests/winetests/user32/dce.c
rostests/winetests/user32/dialog.c
rostests/winetests/user32/input.c
rostests/winetests/user32/menu.c
rostests/winetests/user32/monitor.c
rostests/winetests/user32/msg.c
rostests/winetests/user32/resource.rc
rostests/winetests/user32/sysparams.c
rostests/winetests/user32/text.c
rostests/winetests/user32/uitools.c
rostests/winetests/user32/wsprintf.c

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