[USER32_WINETEST] Sync with Wine Staging 1.9.11 Part 4. CORE-11368
[reactos.git] / rostests / winetests / user32 / win.c
index 7cdbc6f..74c9ec8 100644 (file)
 #define SPI_GETDESKWALLPAPER 0x0073
 #endif
 
+#ifndef WM_SYSTIMER
+#define WM_SYSTIMER 0x0118
+#endif
+
 #define LONG_PTR INT_PTR
 #define ULONG_PTR UINT_PTR
 
@@ -57,6 +61,7 @@ static int  (WINAPI *pGetWindowRgnBox)(HWND,LPRECT);
 static BOOL (WINAPI *pGetGUIThreadInfo)(DWORD, GUITHREADINFO*);
 static BOOL (WINAPI *pGetProcessDefaultLayout)( DWORD *layout );
 static BOOL (WINAPI *pSetProcessDefaultLayout)( DWORD layout );
+static BOOL (WINAPI *pFlashWindow)( HWND hwnd, BOOL bInvert );
 static BOOL (WINAPI *pFlashWindowEx)( PFLASHWINFO pfwi );
 static DWORD (WINAPI *pSetLayout)(HDC hdc, DWORD layout);
 static DWORD (WINAPI *pGetLayout)(HDC hdc);
@@ -68,6 +73,7 @@ static DWORD num_settext_msgs;
 static HWND hwndMessage;
 static HWND hwndMain, hwndMain2;
 static HHOOK hhook;
+static BOOL app_activated, app_deactivated;
 
 static const char* szAWRClass = "Winsize";
 static HMENU hmenu;
@@ -181,6 +187,8 @@ static BOOL ignore_message( UINT message )
     return (message >= 0xc000 ||
             message == WM_GETICON ||
             message == WM_GETOBJECT ||
+            message == WM_TIMER ||
+            message == WM_SYSTIMER ||
             message == WM_TIMECHANGE ||
             message == WM_DEVICECHANGE);
 }
@@ -644,6 +652,31 @@ static void test_parent_owner(void)
     DestroyWindow( child );
     DestroyWindow( test );
     DestroyWindow( owner );
+
+    /* Test that owner window takes into account WS_CHILD flag even if parent is set by SetParent. */
+    owner = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, desktop );
+    SetParent(owner, hwndMain);
+    check_parents( owner, hwndMain, hwndMain, NULL, NULL, hwndMain, owner );
+    test = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, owner );
+    check_parents( test, desktop, owner, NULL, owner, test, test );
+    DestroyWindow( owner );
+    DestroyWindow( test );
+
+    owner = create_tool_window( WS_VISIBLE | WS_CHILD, desktop );
+    SetParent(owner, hwndMain);
+    check_parents( owner, hwndMain, hwndMain, hwndMain, NULL, hwndMain, hwndMain );
+    test = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, owner );
+    check_parents( test, desktop, hwndMain, NULL, hwndMain, test, test );
+    DestroyWindow( owner );
+    DestroyWindow( test );
+
+    owner = create_tool_window( WS_VISIBLE | WS_POPUP | WS_CHILD, desktop );
+    SetParent(owner, hwndMain);
+    check_parents( owner, hwndMain, hwndMain, NULL, NULL, hwndMain, owner );
+    test = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, owner );
+    check_parents( test, desktop, owner, NULL, owner, test, test );
+    DestroyWindow( owner );
+    DestroyWindow( test );
 }
 
 static BOOL CALLBACK enum_proc( HWND hwnd, LPARAM lParam)
@@ -717,6 +750,13 @@ static void test_enum_thread_windows(void)
     CloseHandle( handle );
 }
 
+static struct wm_gettext_override_data
+{
+    BOOL   enabled; /* when 1 bypasses default procedure */
+    char  *buff;    /* expected text buffer pointer */
+    WCHAR *buffW;   /* same, for W test */
+} g_wm_gettext_override;
+
 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 {
     switch (msg)
@@ -798,10 +838,40 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR
             break;
         case WM_GETTEXT:
             num_gettext_msgs++;
+            if (g_wm_gettext_override.enabled)
+            {
+                char *text = (char*)lparam;
+                ok(g_wm_gettext_override.buff == text, "expected buffer %p, got %p\n", g_wm_gettext_override.buff, text);
+                ok(*text == 0, "expected empty string buffer %x\n", *text);
+                return 0;
+            }
             break;
         case WM_SETTEXT:
             num_settext_msgs++;
             break;
+        case WM_ACTIVATEAPP:
+            if (wparam) app_activated = TRUE;
+            else app_deactivated = TRUE;
+            break;
+    }
+
+    return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+static LRESULT WINAPI main_window_procW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+        case WM_GETTEXT:
+            num_gettext_msgs++;
+            if (g_wm_gettext_override.enabled)
+            {
+                WCHAR *text = (WCHAR*)lparam;
+                ok(g_wm_gettext_override.buffW == text, "expected buffer %p, got %p\n", g_wm_gettext_override.buffW, text);
+                ok(*text == 0, "expected empty string buffer %x\n", *text);
+                return 0;
+            }
+            break;
     }
 
     return DefWindowProcA(hwnd, msg, wparam, lparam);
@@ -832,8 +902,11 @@ static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR
     return DefWindowProcA(hwnd, msg, wparam, lparam);
 }
 
+static const WCHAR mainclassW[] = {'M','a','i','n','W','i','n','d','o','w','C','l','a','s','s','W',0};
+
 static BOOL RegisterWindowClasses(void)
 {
+    WNDCLASSW clsW;
     WNDCLASSA cls;
 
     cls.style = CS_DBLCLKS;
@@ -849,6 +922,19 @@ static BOOL RegisterWindowClasses(void)
 
     if(!RegisterClassA(&cls)) return FALSE;
 
+    clsW.style = CS_DBLCLKS;
+    clsW.lpfnWndProc = main_window_procW;
+    clsW.cbClsExtra = 0;
+    clsW.cbWndExtra = 0;
+    clsW.hInstance = GetModuleHandleA(0);
+    clsW.hIcon = 0;
+    clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
+    clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
+    clsW.lpszMenuName = NULL;
+    clsW.lpszClassName = mainclassW;
+
+    if(!RegisterClassW(&clsW)) return FALSE;
+
     cls.style = 0;
     cls.lpfnWndProc = tool_window_procA;
     cls.cbClsExtra = 0;
@@ -928,6 +1014,52 @@ static void FixedAdjustWindowRectEx(RECT* rc, LONG style, BOOL menu, LONG exstyl
        rc->bottom += GetSystemMetrics(SM_CYHSCROLL);
 }
 
+/* reimplement it to check that the Wine algorithm gives the correct result */
+static void wine_AdjustWindowRectEx( RECT *rect, LONG style, BOOL menu, LONG exStyle )
+{
+    int adjust;
+
+    if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
+        WS_EX_STATICEDGE)
+    {
+        adjust = 1; /* for the outer frame always present */
+    }
+    else
+    {
+        adjust = 0;
+        if ((exStyle & WS_EX_DLGMODALFRAME) ||
+            (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
+    }
+    if (style & WS_THICKFRAME)
+        adjust += GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME); /* The resize border */
+    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
+        (exStyle & WS_EX_DLGMODALFRAME))
+        adjust++; /* The other border */
+
+    InflateRect (rect, adjust, adjust);
+
+    if ((style & WS_CAPTION) == WS_CAPTION)
+    {
+        if (exStyle & WS_EX_TOOLWINDOW)
+            rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
+        else
+            rect->top -= GetSystemMetrics(SM_CYCAPTION);
+    }
+    if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
+
+    if (exStyle & WS_EX_CLIENTEDGE)
+        InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
+
+    if (style & WS_VSCROLL)
+    {
+        if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
+            rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
+        else
+            rect->right += GetSystemMetrics(SM_CXVSCROLL);
+    }
+    if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
+}
+
 static void test_nonclient_area(HWND hwnd)
 {
     DWORD style, exstyle;
@@ -955,6 +1087,14 @@ static void test_nonclient_area(HWND hwnd)
        style, exstyle, menu, rc_window.left, rc_window.top, rc_window.right, rc_window.bottom,
        rc.left, rc.top, rc.right, rc.bottom);
 
+    CopyRect(&rc, &rc_client);
+    MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
+    wine_AdjustWindowRectEx(&rc, style, menu, exstyle);
+    ok(EqualRect(&rc, &rc_window),
+       "window rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, win=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n",
+       style, exstyle, menu, rc_window.left, rc_window.top, rc_window.right, rc_window.bottom,
+       rc.left, rc.top, rc.right, rc.bottom);
+
 
     CopyRect(&rc, &rc_window);
     DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc);
@@ -1240,7 +1380,7 @@ static char mdi_lParam_test_message[] = "just a test string";
 static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
 {
     MDICREATESTRUCTA mdi_cs;
-    HWND mdi_child;
+    HWND mdi_child, hwnd, exp_hwnd;
     INT_PTR id;
     static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0};
     static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0};
@@ -1259,6 +1399,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == first_id, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0;
+    ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd);
     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
 
@@ -1267,6 +1410,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == first_id, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
 
@@ -1281,6 +1426,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
         ok(mdi_child != 0, "MDI child creation failed\n");
         id = GetWindowLongPtrA(mdi_child, GWLP_ID);
         ok(id == first_id, "wrong child id %ld\n", id);
+        hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+        ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
     }
@@ -1303,6 +1450,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     {
         id = GetWindowLongPtrA(mdi_child, GWLP_ID);
         ok(id == first_id, "wrong child id %ld\n", id);
+        hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+        exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0;
+        ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd);
         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
     }
@@ -1316,6 +1466,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == first_id, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0;
+    ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd);
     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
 
@@ -1328,6 +1481,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == first_id, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
 
@@ -1346,6 +1501,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
         ok(mdi_child != 0, "MDI child creation failed\n");
         id = GetWindowLongPtrA(mdi_child, GWLP_ID);
         ok(id == first_id, "wrong child id %ld\n", id);
+        hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+        ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
     }
@@ -1369,6 +1526,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     {
         id = GetWindowLongPtrA(mdi_child, GWLP_ID);
         ok(id == first_id, "wrong child id %ld\n", id);
+        hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+        exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0;
+        ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd);
         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
     }
@@ -1382,6 +1542,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == first_id, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0;
+    ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd);
     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
 
@@ -1394,6 +1557,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == first_id, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
     ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
 
@@ -1412,6 +1577,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
         ok(mdi_child != 0, "MDI child creation failed\n");
         id = GetWindowLongPtrA(mdi_child, GWLP_ID);
         ok(id == first_id, "wrong child id %ld\n", id);
+        hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+        ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
     }
@@ -1435,6 +1602,9 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     {
         id = GetWindowLongPtrA(mdi_child, GWLP_ID);
         ok(id == first_id, "wrong child id %ld\n", id);
+        hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+        exp_hwnd = (GetWindowLongW(mdi_child, GWL_STYLE) & WS_VISIBLE) ? mdi_child : 0;
+        ok(hwnd == exp_hwnd, "WM_MDIGETACTIVE should return %p, got %p\n", exp_hwnd, hwnd);
         SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
         ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n");
     }
@@ -1460,6 +1630,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == 0, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     DestroyWindow(mdi_child);
 
     mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child",
@@ -1471,6 +1643,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == 0, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     DestroyWindow(mdi_child);
 
     /* maximized child */
@@ -1483,6 +1657,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == 0, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     DestroyWindow(mdi_child);
 
     trace("Creating maximized child with a caption\n");
@@ -1495,6 +1671,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == 0, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     DestroyWindow(mdi_child);
 
     trace("Creating maximized child with a caption and a thick frame\n");
@@ -1507,6 +1685,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     ok(mdi_child != 0, "MDI child creation failed\n");
     id = GetWindowLongPtrA(mdi_child, GWLP_ID);
     ok(id == 0, "wrong child id %ld\n", id);
+    hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd);
     DestroyWindow(mdi_child);
 }
 
@@ -1819,51 +1999,7 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA
     switch (msg)
     {
         case WM_CREATE:
-        {
-            CLIENTCREATESTRUCT client_cs;
-            RECT rc;
-
-            GetClientRect(hwnd, &rc);
-
-            client_cs.hWindowMenu = 0;
-            client_cs.idFirstChild = 1;
-
-            /* MDIClient without MDIS_ALLCHILDSTYLES */
-            mdi_client = CreateWindowExA(0, "mdiclient",
-                                         NULL,
-                                         WS_CHILD /*| WS_VISIBLE*/,
-                                          /* tests depend on a not zero MDIClient size */
-                                         0, 0, rc.right, rc.bottom,
-                                         hwnd, 0, GetModuleHandleA(NULL),
-                                         &client_cs);
-            assert(mdi_client);
-            test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild);
-            DestroyWindow(mdi_client);
-
-            /* MDIClient with MDIS_ALLCHILDSTYLES */
-            mdi_client = CreateWindowExA(0, "mdiclient",
-                                         NULL,
-                                         WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/,
-                                          /* tests depend on a not zero MDIClient size */
-                                         0, 0, rc.right, rc.bottom,
-                                         hwnd, 0, GetModuleHandleA(NULL),
-                                         &client_cs);
-            assert(mdi_client);
-            test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild);
-            DestroyWindow(mdi_client);
-
-            /* Test child window stack management */
-            mdi_client = CreateWindowExA(0, "mdiclient",
-                                         NULL,
-                                         WS_CHILD,
-                                         0, 0, rc.right, rc.bottom,
-                                         hwnd, 0, GetModuleHandleA(NULL),
-                                         &client_cs);
-            assert(mdi_client);
-            test_MDI_child_stack(mdi_client);
-            DestroyWindow(mdi_client);
-            break;
-        }
+            return 1;
 
         case WM_WINDOWPOSCHANGED:
         {
@@ -1943,8 +2079,12 @@ static BOOL mdi_RegisterWindowClasses(void)
 
 static void test_mdi(void)
 {
-    HWND mdi_hwndMain;
-    /*MSG msg;*/
+    static const DWORD style[] = { 0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL | WS_VSCROLL };
+    HWND mdi_hwndMain, mdi_client;
+    CLIENTCREATESTRUCT client_cs;
+    RECT rc;
+    DWORD i;
+    MSG msg;
 
     if (!mdi_RegisterWindowClasses()) assert(0);
 
@@ -1955,6 +2095,178 @@ static void test_mdi(void)
                                    GetDesktopWindow(), 0,
                                    GetModuleHandleA(NULL), NULL);
     assert(mdi_hwndMain);
+
+    GetClientRect(mdi_hwndMain, &rc);
+
+    client_cs.hWindowMenu = 0;
+    client_cs.idFirstChild = 1;
+
+    for (i = 0; i < sizeof(style)/sizeof(style[0]); i++)
+    {
+        HWND mdi_child;
+        SCROLLINFO si;
+        BOOL ret, gotit;
+
+        mdi_client = CreateWindowExA(0, "mdiclient", NULL,
+                                 WS_CHILD | style[i],
+                                 0, 0, rc.right, rc.bottom,
+                                 mdi_hwndMain, 0, 0, &client_cs);
+        ok(mdi_client != 0, "MDI client creation failed\n");
+
+        mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child",
+                                0,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                CW_USEDEFAULT, CW_USEDEFAULT,
+                                mdi_client, 0, 0,
+                                mdi_lParam_test_message);
+        ok(mdi_child != 0, "MDI child creation failed\n");
+
+        si.cbSize = sizeof(si);
+        si.fMask = SIF_ALL;
+        ret = GetScrollInfo(mdi_client, SB_HORZ, &si);
+        if (style[i] & (WS_HSCROLL | WS_VSCROLL))
+        {
+            ok(ret, "style %#x: GetScrollInfo(SB_HORZ) failed\n", style[i]);
+            ok(si.nPage == 0, "expected 0\n");
+            ok(si.nPos == 0, "expected 0\n");
+            ok(si.nTrackPos == 0, "expected 0\n");
+            ok(si.nMin == 0, "expected 0\n");
+            ok(si.nMax == 100, "expected 100\n");
+        }
+        else
+            ok(!ret, "style %#x: GetScrollInfo(SB_HORZ) should fail\n", style[i]);
+
+        ret = GetScrollInfo(mdi_client, SB_VERT, &si);
+        if (style[i] & (WS_HSCROLL | WS_VSCROLL))
+        {
+            ok(ret, "style %#x: GetScrollInfo(SB_VERT) failed\n", style[i]);
+            ok(si.nPage == 0, "expected 0\n");
+            ok(si.nPos == 0, "expected 0\n");
+            ok(si.nTrackPos == 0, "expected 0\n");
+            ok(si.nMin == 0, "expected 0\n");
+            ok(si.nMax == 100, "expected 100\n");
+        }
+        else
+            ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]);
+
+        SetWindowPos(mdi_child, 0, -100, -100, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+
+        si.cbSize = sizeof(si);
+        si.fMask = SIF_ALL;
+        ret = GetScrollInfo(mdi_client, SB_HORZ, &si);
+        if (style[i] & (WS_HSCROLL | WS_VSCROLL))
+        {
+            ok(ret, "style %#x: GetScrollInfo(SB_HORZ) failed\n", style[i]);
+            ok(si.nPage == 0, "expected 0\n");
+            ok(si.nPos == 0, "expected 0\n");
+            ok(si.nTrackPos == 0, "expected 0\n");
+            ok(si.nMin == 0, "expected 0\n");
+            ok(si.nMax == 100, "expected 100\n");
+        }
+        else
+            ok(!ret, "style %#x: GetScrollInfo(SB_HORZ) should fail\n", style[i]);
+
+        ret = GetScrollInfo(mdi_client, SB_VERT, &si);
+        if (style[i] & (WS_HSCROLL | WS_VSCROLL))
+        {
+            ok(ret, "style %#x: GetScrollInfo(SB_VERT) failed\n", style[i]);
+            ok(si.nPage == 0, "expected 0\n");
+            ok(si.nPos == 0, "expected 0\n");
+            ok(si.nTrackPos == 0, "expected 0\n");
+            ok(si.nMin == 0, "expected 0\n");
+            ok(si.nMax == 100, "expected 100\n");
+        }
+        else
+            ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]);
+
+        gotit = FALSE;
+        while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+        {
+            if (msg.message == WM_MOUSEMOVE || msg.message == WM_PAINT)
+            {
+                DispatchMessageA(&msg);
+                continue;
+            }
+
+            if (msg.message == 0x003f) /* WM_MDICALCCHILDSCROLL ??? */
+            {
+                ok(msg.hwnd == mdi_client, "message 0x003f should be posted to mdiclient\n");
+                gotit = TRUE;
+            }
+            else
+                ok(msg.hwnd != mdi_client, "message %04x should not be posted to mdiclient\n", msg.message);
+            DispatchMessageA(&msg);
+        }
+        ok(gotit, "message 0x003f should appear after SetWindowPos\n");
+
+        si.cbSize = sizeof(si);
+        si.fMask = SIF_ALL;
+        ret = GetScrollInfo(mdi_client, SB_HORZ, &si);
+        if (style[i] & (WS_HSCROLL | WS_VSCROLL))
+        {
+            ok(ret, "style %#x: GetScrollInfo(SB_HORZ) failed\n", style[i]);
+todo_wine
+            ok(si.nPage != 0, "expected !0\n");
+            ok(si.nPos == 0, "expected 0\n");
+            ok(si.nTrackPos == 0, "expected 0\n");
+            ok(si.nMin != 0, "expected !0\n");
+            ok(si.nMax != 100, "expected !100\n");
+        }
+        else
+            ok(!ret, "style %#x: GetScrollInfo(SB_HORZ) should fail\n", style[i]);
+
+        ret = GetScrollInfo(mdi_client, SB_VERT, &si);
+        if (style[i] & (WS_HSCROLL | WS_VSCROLL))
+        {
+            ok(ret, "style %#x: GetScrollInfo(SB_VERT) failed\n", style[i]);
+todo_wine
+            ok(si.nPage != 0, "expected !0\n");
+            ok(si.nPos == 0, "expected 0\n");
+            ok(si.nTrackPos == 0, "expected 0\n");
+            ok(si.nMin != 0, "expected !0\n");
+            ok(si.nMax != 100, "expected !100\n");
+        }
+        else
+            ok(!ret, "style %#x: GetScrollInfo(SB_VERT) should fail\n", style[i]);
+
+        DestroyWindow(mdi_child);
+        DestroyWindow(mdi_client);
+    }
+
+    /* MDIClient without MDIS_ALLCHILDSTYLES */
+    mdi_client = CreateWindowExA(0, "mdiclient",
+                                 NULL,
+                                 WS_CHILD /*| WS_VISIBLE*/,
+                                  /* tests depend on a not zero MDIClient size */
+                                 0, 0, rc.right, rc.bottom,
+                                 mdi_hwndMain, 0, GetModuleHandleA(NULL),
+                                 &client_cs);
+    assert(mdi_client);
+    test_MDI_create(mdi_hwndMain, mdi_client, client_cs.idFirstChild);
+    DestroyWindow(mdi_client);
+
+    /* MDIClient with MDIS_ALLCHILDSTYLES */
+    mdi_client = CreateWindowExA(0, "mdiclient",
+                                 NULL,
+                                 WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/,
+                                  /* tests depend on a not zero MDIClient size */
+                                 0, 0, rc.right, rc.bottom,
+                                 mdi_hwndMain, 0, GetModuleHandleA(NULL),
+                                 &client_cs);
+    assert(mdi_client);
+    test_MDI_create(mdi_hwndMain, mdi_client, client_cs.idFirstChild);
+    DestroyWindow(mdi_client);
+
+    /* Test child window stack management */
+    mdi_client = CreateWindowExA(0, "mdiclient",
+                                 NULL,
+                                 WS_CHILD,
+                                 0, 0, rc.right, rc.bottom,
+                                 mdi_hwndMain, 0, GetModuleHandleA(NULL),
+                                 &client_cs);
+    assert(mdi_client);
+    test_MDI_child_stack(mdi_client);
+    DestroyWindow(mdi_client);
 /*
     while(GetMessage(&msg, 0, 0, 0))
     {
@@ -3200,7 +3512,7 @@ static BOOL peek_message( MSG *msg )
     do
     {
         ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE);
-    } while (ret && (msg->message == WM_TIMER || ignore_message(msg->message)));
+    } while (ret && ignore_message(msg->message));
     return ret;
 }
 
@@ -3364,7 +3676,7 @@ static void test_mouse_input(HWND hwnd)
     /* FIXME: SetCursorPos in Wine generates additional WM_MOUSEMOVE message */
     while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
     {
-        if (msg.message == WM_TIMER || ignore_message(msg.message)) continue;
+        if (ignore_message(msg.message)) continue;
         ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE,
            "hwnd %p message %04x\n", msg.hwnd, msg.message);
         DispatchMessageA(&msg);
@@ -3884,10 +4196,8 @@ static void check_window_style(DWORD dwStyleIn, DWORD dwExStyleIn, DWORD dwStyle
         dwExStyleOut = dwExStyleIn & ~WS_EX_WINDOWEDGE;
     ok(dwActualStyle == dwStyleOut, "expected style %#x, got %#x\n", dwStyleOut, dwActualStyle);
     /* FIXME: Remove the condition below once Wine is fixed */
-    if (dwActualExStyle != dwExStyleOut)
-    todo_wine ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle);
-    else
-    ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle);
+    todo_wine_if (dwActualExStyle != dwExStyleOut)
+        ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle);
 
     DestroyWindow(hwnd);
     if (hwndParent) DestroyWindow(hwndParent);
@@ -3946,6 +4256,74 @@ static INT_PTR WINAPI empty_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
     return 0;
 }
 
+static INT_PTR WINAPI empty_dlg_proc3(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_INITDIALOG)
+        EndDialog(hwnd, 0);
+
+    return 0;
+}
+
+struct dialog_param
+{
+    HWND parent, grand_parent;
+    DLGTEMPLATE *dlg_data;
+};
+
+static INT_PTR WINAPI empty_dlg_proc2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_INITDIALOG)
+    {
+        DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
+        struct dialog_param *param = (struct dialog_param *)lparam;
+        BOOL parent_is_child;
+        HWND disabled_hwnd;
+
+        parent_is_child = (GetWindowLongA(param->parent, GWL_STYLE) & (WS_POPUP | WS_CHILD)) == WS_CHILD;
+
+        ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd);
+        if (parent_is_child)
+        {
+            ok(IsWindowEnabled(param->parent), "wrong state for %08x\n", style);
+            disabled_hwnd = param->grand_parent;
+        }
+        else
+        {
+            ok(!IsWindowEnabled(param->parent), "wrong state for %08x\n", style);
+            disabled_hwnd = param->parent;
+        }
+
+        if (param->grand_parent)
+        {
+            if (parent_is_child)
+                ok(!IsWindowEnabled(param->grand_parent), "wrong state for %08x\n", style);
+            else
+                ok(IsWindowEnabled(param->grand_parent), "wrong state for %08x\n", style);
+        }
+
+        DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, disabled_hwnd, empty_dlg_proc3, 0);
+        ok(IsWindowEnabled(disabled_hwnd), "wrong state for %08x\n", style);
+
+        ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd);
+        ok(IsWindowEnabled(param->parent), "wrong state for %p\n", param->parent);
+        if (param->grand_parent)
+            ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08x)\n", param->grand_parent, style);
+
+        DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0);
+        ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd);
+        ok(IsWindowEnabled(param->parent), "wrong state for %p\n", param->parent);
+        if (param->grand_parent)
+            ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08x)\n", param->grand_parent, style);
+
+        param->dlg_data->style |= WS_CHILD;
+        DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0);
+        ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style);
+
+        EndDialog(hwnd, 0);
+    }
+    return 0;
+}
+
 static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_out, DWORD ex_style_out)
 {
     struct
@@ -3957,11 +4335,19 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou
         WCHAR caption[1];
     } dlg_data;
     DWORD style, ex_style;
-    HWND hwnd, parent = 0;
+    HWND hwnd, grand_parent = 0, parent = 0;
+    struct dialog_param param;
 
     if (style_in & WS_CHILD)
-        parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW,
+    {
+        grand_parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW,
                                 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+        ok(grand_parent != 0, "grand_parent creation failed\n");
+    }
+
+    parent = CreateWindowExA(0, "static", NULL, style_in,
+                             0, 0, 0, 0, grand_parent, NULL, NULL, NULL);
+    ok(parent != 0, "parent creation failed, style %#x\n", style_in);
 
     dlg_data.dt.style = style_in;
     dlg_data.dt.dwExtendedStyle = ex_style_in;
@@ -3985,6 +4371,8 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou
     ok(style == (style_out | DS_3DLOOK), "got %#x\n", style);
     ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style);
 
+    ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#x)\n", style_in);
+
     /* try setting the styles explicitly */
     SetWindowLongA(hwnd, GWL_EXSTYLE, ex_style_in);
     style = GetWindowLongA(hwnd, GWL_STYLE);
@@ -4014,13 +4402,22 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou
     else
         ex_style_out = ex_style_in & ~WS_EX_WINDOWEDGE;
     /* FIXME: Remove the condition below once Wine is fixed */
-    if (ex_style != ex_style_out)
-    todo_wine ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style);
-    else
-    ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style);
+    todo_wine_if (ex_style != ex_style_out)
+        ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style);
 
     DestroyWindow(hwnd);
+
+    param.parent = parent;
+    param.grand_parent = grand_parent;
+    param.dlg_data = &dlg_data.dt;
+    DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, parent, empty_dlg_proc2, (LPARAM)&param);
+
+    ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#x)\n", style_in);
+    if (grand_parent)
+        ok(IsWindowEnabled(grand_parent), "wrong grand parent state (dialog style %#x)\n", style_in);
+
     DestroyWindow(parent);
+    DestroyWindow(grand_parent);
 }
 
 static void test_dialog_styles(void)
@@ -4110,6 +4507,233 @@ static void test_dialog_styles(void)
     }
 }
 
+struct dlg_parent_param
+{
+    HWND ga_parent;
+    HWND gwl_parent;
+    HWND get_parent;
+    HWND owner;
+    HWND root;
+    HWND ga_root_owner;
+};
+
+static INT_PTR WINAPI parent_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_INITDIALOG) {
+        struct dlg_parent_param *param = (void*)lparam;
+        check_parents(hwnd, param->ga_parent, param->gwl_parent, param->get_parent, param->owner,
+                      param->root ? param->root : hwnd, param->ga_root_owner ? param->ga_root_owner : hwnd);
+
+        ok(!IsWindowEnabled(param->gwl_parent), "parent is not disabled\n");
+        EndDialog(hwnd, 2);
+        ok(IsWindowEnabled(param->gwl_parent), "parent is not enabled\n");
+    }
+
+    return 0;
+}
+
+static INT_PTR WINAPI reparent_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_INITDIALOG) {
+        ok(!IsWindowEnabled(GetParent(hwnd)), "parent is not disabled\n");
+        SetParent(hwnd, (HWND)lparam);
+    }
+
+    return 0;
+}
+
+static INT_PTR WINAPI reparent_owned_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_INITDIALOG) {
+        HWND new_parent = (HWND)lparam;
+        HWND owner = GetWindow(hwnd, GW_OWNER);
+        ok(!IsWindowEnabled(owner), "owner is not disabled\n");
+        SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_CHILD);
+        SetParent(hwnd, new_parent);
+        ok(GetParent(hwnd) == new_parent, "GetParent(hwnd) = %p, expected %p\n", GetParent(hwnd), new_parent);
+        PostMessageA(hwnd, WM_QUIT, 0, 0);
+    }
+
+    return 0;
+}
+
+static LRESULT WINAPI reparent_dialog_owner_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_ENTERIDLE) {
+        HWND dialog = (HWND)lparam;
+        HWND owner = GetParent(dialog);
+        /* EndDialog will enable owner */
+        EnableWindow(owner, FALSE);
+        EndDialog(dialog, 2);
+        ok(IsWindowEnabled(owner), "owner is not enabled\n");
+        /* ...but it won't be enabled on dialog exit */
+        EnableWindow(owner, FALSE);
+    }
+    return DefWindowProcA( hwnd, msg, wparam, lparam );
+}
+
+static LRESULT WINAPI post_quit_dialog_owner_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_ENTERIDLE) {
+        HWND dialog = (HWND)lparam;
+        PostMessageA(dialog, WM_QUIT, 0, 0);
+    }
+    return DefWindowProcA( hwnd, msg, wparam, lparam );
+}
+
+static LRESULT WINAPI destroy_dialog_owner_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if (msg == WM_ENTERIDLE) {
+        HWND dialog = (HWND)lparam;
+        DestroyWindow(dialog);
+    }
+    return DefWindowProcA( hwnd, msg, wparam, lparam );
+}
+
+static void test_dialog_parent(void)
+{
+    HWND dialog, parent, child, child2, other, desktop = GetDesktopWindow();
+    struct dlg_parent_param param;
+    INT_PTR ret;
+    struct
+    {
+        DLGTEMPLATE dt;
+        WORD menu_name;
+        WORD class_id;
+        WORD class_atom;
+        WCHAR caption[1];
+    } dlg_data;
+
+    dlg_data.dt.dwExtendedStyle = 0;
+    dlg_data.dt.cdit = 0;
+    dlg_data.dt.x = 0;
+    dlg_data.dt.y = 0;
+    dlg_data.dt.cx = 100;
+    dlg_data.dt.cy = 100;
+    dlg_data.menu_name = 0;
+    dlg_data.class_id = 0;
+    dlg_data.class_atom = 0;
+    dlg_data.caption[0] = 0;
+
+    parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    /* Create a child without WS_CHILD flag. It's a valid owner window. */
+    child = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    SetParent(child, parent);
+    /* Regular child. If passed as an owner, its parent will be true owner window. */
+    child2 = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, child, NULL, NULL, NULL);
+
+    trace("parent %p child %p child2 %p desktop %p\n", parent, child, child2, desktop);
+
+    /* When dialog is created with WS_CHILD style, its parent depends on function used to create it. */
+    dlg_data.dt.style = WS_CHILD;
+
+    /* CreateDialogIndirectParam uses passed parent as dialog parent. */
+    dialog = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, empty_dlg_proc, 0);
+    ok(dialog != 0, "dialog creation failed\n");
+    check_parents(dialog, child2, child2, child2, NULL, parent, child);
+
+    ok(IsWindowEnabled(child2), "child2 is disabled\n");
+    EnableWindow(child2, FALSE);
+    EndDialog(dialog, 0);
+    ok(IsWindowEnabled(child2), "child2 is not enabled\n");
+    DestroyWindow(dialog);
+
+    /* DialogBoxIndirectParam uses the first parent of passed owner that's not a child window as dialog
+     * parent (like in case of dialog with owner). */
+    param.ga_parent = param.gwl_parent = param.get_parent = child;
+    param.owner = NULL;
+    param.root = parent;
+    param.ga_root_owner = child;
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)&param);
+    ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret);
+
+    /* Dialogs without WS_CHILD behave as expected, they use passed owner just like CreateWindow does. */
+    dlg_data.dt.style = WS_OVERLAPPEDWINDOW;
+
+    dialog = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, empty_dlg_proc, 0);
+    ok(dialog != 0, "dialog creation failed\n");
+    check_parents(dialog, desktop, child, NULL, child, dialog, dialog);
+
+    ok(IsWindowEnabled(child), "child is disabled\n");
+    EnableWindow(child, FALSE);
+    EndDialog(dialog, 0);
+    ok(IsWindowEnabled(child), "child is not enabled\n");
+    DestroyWindow(dialog);
+
+    param.ga_parent = desktop;
+    param.gwl_parent = child;
+    param.get_parent = NULL;
+    param.owner = child;
+    param.root = param.ga_root_owner = NULL;
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)&param);
+    ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret);
+
+    other = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+    SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)reparent_dialog_owner_proc);
+
+    /* When dialog is created with WS_CHILD|WS_POPUP style, we have an owner. */
+    dlg_data.dt.style = WS_CHILD|WS_POPUP;
+
+    dialog = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, empty_dlg_proc, 0);
+    ok(dialog != 0, "dialog creation failed\n");
+    check_parents(dialog, desktop, child, child, child, dialog, child);
+
+    ok(IsWindowEnabled(child), "child is disabled\n");
+    EnableWindow(child, FALSE);
+    EndDialog(dialog, 0);
+    ok(IsWindowEnabled(child), "child is not enabled\n");
+    DestroyWindow(dialog);
+
+    param.ga_parent = desktop;
+    param.gwl_parent = param.get_parent = child;
+    param.owner = child;
+    param.root = NULL;
+    param.ga_root_owner = child;
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)&param);
+    ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret);
+
+    /* If we change parent in WM_INITDIALOG for WS_CHILD dialog WM_ENTERIDLE is still sent to the original
+     * parent. EndDialog will enable the new parent. */
+    EnableWindow(child, TRUE);
+    EnableWindow(other, FALSE);
+    dlg_data.dt.style = WS_CHILD;
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, reparent_dlg_proc, (LPARAM)other);
+    ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret);
+    ok(!IsWindowEnabled(other), "other is not disabled\n");
+    ok(!IsWindowEnabled(child), "child is not disabled\n");
+    ok(IsWindowEnabled(child2), "child2 is not enabled\n");
+    EnableWindow(child, TRUE);
+
+    /* If we change parent and style in WM_INITDIALOG for dialog with an owner to make it true child
+     * (thus GetParent() will return the new parent instead of an owner), WM_ENTERIDLE is still sent
+     * to the original parent. EndDialog will enable the new parent. */
+    EnableWindow(other, FALSE);
+    dlg_data.dt.style = WS_OVERLAPPED;
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, reparent_owned_dlg_proc, (LPARAM)other);
+    ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret);
+    ok(!IsWindowEnabled(other), "other is not disabled\n");
+    ok(!IsWindowEnabled(child), "child is not disabled\n");
+    ok(IsWindowEnabled(child2), "child2 is not enabled\n");
+    EnableWindow(child, TRUE);
+    EnableWindow(other, TRUE);
+
+    /* Quit dialog message loop by sending WM_QUIT message. Dialog owner is not enabled. */
+    SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)post_quit_dialog_owner_proc);
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, other, empty_dlg_proc, 0);
+    ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret);
+    ok(!IsWindowEnabled(other), "other is enabled\n");
+    EnableWindow(other, TRUE);
+
+    /* Quit dialog message loop by destroying the window. Dialog owner is not enabled. */
+    SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)destroy_dialog_owner_proc);
+    ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, other, empty_dlg_proc, 0);
+    ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret);
+    ok(!IsWindowEnabled(other), "other is enabled\n");
+    EnableWindow(other, TRUE);
+
+    DestroyWindow(parent);
+}
+
 static void test_scrollwindow( HWND hwnd)
 {
     HDC hdc;
@@ -4217,11 +4841,25 @@ static void test_scrollvalidate( HWND parent)
             rcu.left,rcu.top,rcu.right,rcu.bottom);
     ReleaseDC( hwnd1, hdc);
 
-    /* test scrolling a window with an update region */
+    /* test scrolling a rect by more than its size */
     DestroyWindow( hwnd2);
     ValidateRect( hwnd1, NULL);
     SetRect( &rc, 40,40, 50,50);
     InvalidateRect( hwnd1, &rc, 1);
+    ScrollWindowEx( hwnd1, -20, 0, &rc, NULL, hrgn, &rcu,
+      SW_SCROLLCHILDREN | SW_INVALIDATE);
+    if (winetest_debug > 0) dump_region(hrgn);
+    SetRectRgn( exprgn, 20, 40, 30, 50);
+    SetRectRgn( tmprgn, 40, 40, 50, 50);
+    CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
+    ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
+    ok( rcu.left == 20 && rcu.top == 40 && rcu.right == 50 && rcu.bottom == 50,
+        "unexpected update rect: %d,%d - %d,%d\n", rcu.left,rcu.top,rcu.right,rcu.bottom);
+
+    /* test scrolling a window with an update region */
+    ValidateRect( hwnd1, NULL);
+    SetRect( &rc, 40,40, 50,50);
+    InvalidateRect( hwnd1, &rc, 1);
     GetClientRect( hwnd1, &rc);
     cliprc=rc;
     ScrollWindowEx( hwnd1, -10, 0, &rc, &cliprc, hrgn, &rcu,
@@ -4506,26 +5144,16 @@ static BOOL AWR_init(void)
 
 static void test_AWR_window_size(BOOL menu)
 {
-    LONG styles[] = {
-       WS_POPUP,
-       WS_MAXIMIZE, WS_BORDER, WS_DLGFRAME, 
-       WS_SYSMENU, 
-       WS_THICKFRAME,
-       WS_MINIMIZEBOX, WS_MAXIMIZEBOX,
-       WS_HSCROLL, WS_VSCROLL
+    static const DWORD styles[] = {
+        WS_POPUP, WS_MAXIMIZE, WS_BORDER, WS_DLGFRAME, WS_CAPTION, WS_SYSMENU,
+        WS_THICKFRAME, WS_MINIMIZEBOX, WS_MAXIMIZEBOX, WS_HSCROLL, WS_VSCROLL
     };
-    LONG exStyles[] = {
-       WS_EX_CLIENTEDGE,
-       WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE,
-       WS_EX_APPWINDOW,
-#if 0
-       /* These styles have problems on (at least) WinXP (SP2) and Wine */
-       WS_EX_DLGMODALFRAME, 
-       WS_EX_STATICEDGE, 
-#endif
+    static const DWORD exStyles[] = {
+       WS_EX_CLIENTEDGE, WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE, WS_EX_APPWINDOW,
+       WS_EX_DLGMODALFRAME, WS_EX_DLGMODALFRAME | WS_EX_STATICEDGE
     };
 
-    int i;    
+    unsigned int i;
 
     /* A exhaustive check of all the styles takes too long
      * so just do a (hopefully representative) sample
@@ -4537,6 +5165,33 @@ static void test_AWR_window_size(BOOL menu)
         test_AWRwindow(szAWRClass, WS_THICKFRAME, exStyles[i], menu);
     }
 }
+
+static void test_AWR_flags(void)
+{
+    static const DWORD styles[] = { WS_POPUP, WS_BORDER, WS_DLGFRAME, WS_THICKFRAME };
+    static const DWORD exStyles[] = { WS_EX_CLIENTEDGE, WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE,
+                                      WS_EX_APPWINDOW, WS_EX_DLGMODALFRAME, WS_EX_STATICEDGE };
+
+    DWORD i, j, k, style, exstyle;
+    RECT rect, rect2;
+
+    for (i = 0; i < (1 << COUNTOF(styles)); i++)
+    {
+        for (k = style = 0; k < COUNTOF(styles); k++) if (i & (1 << k)) style |= styles[k];
+
+        for (j = 0; j < (1 << COUNTOF(exStyles)); j++)
+        {
+            for (k = exstyle = 0; k < COUNTOF(exStyles); k++) if (j & (1 << k)) exstyle |= exStyles[k];
+            SetRect( &rect, 100, 100, 200, 200 );
+            rect2 = rect;
+            AdjustWindowRectEx( &rect, style, FALSE, exstyle );
+            wine_AdjustWindowRectEx( &rect2, style, FALSE, exstyle );
+            ok( EqualRect( &rect, &rect2 ), "rects do not match: win %d,%d-%d,%d wine %d,%d-%d,%d\n",
+                rect.left, rect.top, rect.right, rect.bottom,
+                rect2.left, rect2.top, rect2.right, rect2.bottom );
+        }
+    }
+}
 #undef COUNTOF
 
 #define SHOWSYSMETRIC(SM) trace(#SM "=%d\n", GetSystemMetrics(SM))
@@ -4562,6 +5217,7 @@ static void test_AdjustWindowRect(void)
 
     test_AWR_window_size(FALSE);
     test_AWR_window_size(TRUE);
+    test_AWR_flags();
 
     DestroyMenu(hmenu);
 }
@@ -4688,8 +5344,8 @@ static void zero_parentdc_test(struct parentdc_test *t)
       t.w.r.f, got.w.r.f)
 
 #define parentdc_todo_field_ok(t, w, r, f, got) \
-  if (t.w##_todo.r.f) todo_wine { parentdc_field_ok(t, w, r, f, got); } \
-  else parentdc_field_ok(t, w, r, f, got)
+  todo_wine_if (t.w##_todo.r.f) \
+      parentdc_field_ok(t, w, r, f, got);
 
 #define parentdc_rect_ok(t, w, r, got) \
   parentdc_todo_field_ok(t, w, r, left, got); \
@@ -5359,7 +6015,7 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
 
     expected_cx = expected_cy = -10;
-    SetRect( &expected_rect, 0, 0, 0, 0 );
+    SetRectEmpty(&expected_rect);
     SetRect( &broken_rect, 0, 0, -10, -10 );
     hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -20, -20, -10, -10, parent, 0, 0, NULL);
     ok( hwnd != 0, "creation failed err %u\n", GetLastError());
@@ -5369,7 +6025,7 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
 
     expected_cx = expected_cy = -200000;
-    SetRect( &expected_rect, 0, 0, 0, 0 );
+    SetRectEmpty(&expected_rect);
     SetRect( &broken_rect, 0, 0, -200000, -200000 );
     hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -300000, -300000, -200000, -200000, parent, 0, 0, NULL);
     ok( hwnd != 0, "creation failed err %u\n", GetLastError());
@@ -5726,11 +6382,12 @@ static DWORD CALLBACK settext_msg_thread( LPVOID arg )
 static void test_gettext(void)
 {
     DWORD tid, num_msgs;
+    WCHAR bufW[32];
     HANDLE thread;
     BOOL success;
     char buf[32];
     INT buf_len;
-    HWND hwnd;
+    HWND hwnd, hwnd2;
     LRESULT r;
     MSG msg;
 
@@ -5745,6 +6402,68 @@ static void test_gettext(void)
     ok( !strcmp(buf, "caption"), "got wrong window text '%s'\n", buf );
     ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs );
 
+    /* other process window */
+    strcpy( buf, "a" );
+    buf_len = GetWindowTextA( GetDesktopWindow(), buf, sizeof(buf) );
+    ok( buf_len == 0, "expected a nonempty window text\n" );
+    ok( *buf == 0, "got wrong window text '%s'\n", buf );
+
+    strcpy( buf, "blah" );
+    buf_len = GetWindowTextA( GetDesktopWindow(), buf, 0 );
+    ok( buf_len == 0, "expected a nonempty window text\n" );
+    ok( !strcmp(buf, "blah"), "got wrong window text '%s'\n", buf );
+
+    bufW[0] = 0xcc;
+    buf_len = GetWindowTextW( GetDesktopWindow(), bufW, 0 );
+    ok( buf_len == 0, "expected a nonempty window text\n" );
+    ok( bufW[0] == 0xcc, "got %x\n", bufW[0] );
+
+    g_wm_gettext_override.enabled = TRUE;
+
+    num_gettext_msgs = 0;
+    memset( buf, 0xcc, sizeof(buf) );
+    g_wm_gettext_override.buff = buf;
+    buf_len = GetWindowTextA( hwnd, buf, sizeof(buf) );
+    ok( buf_len == 0, "got %d\n", buf_len );
+    ok( *buf == 0, "got %x\n", *buf );
+    ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs );
+
+    num_gettext_msgs = 0;
+    strcpy( buf, "blah" );
+    g_wm_gettext_override.buff = buf;
+    buf_len = GetWindowTextA( hwnd, buf, 0 );
+    ok( buf_len == 0, "got %d\n", buf_len );
+    ok( !strcmp(buf, "blah"), "got %s\n", buf );
+    ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs );
+
+    g_wm_gettext_override.enabled = FALSE;
+
+    /* same for W window */
+    hwnd2 = CreateWindowExW( 0, mainclassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL );
+    ok( hwnd2 != 0, "CreateWindowExA error %d\n", GetLastError() );
+
+    g_wm_gettext_override.enabled = TRUE;
+
+    num_gettext_msgs = 0;
+    memset( bufW, 0xcc, sizeof(bufW) );
+    g_wm_gettext_override.buffW = bufW;
+    buf_len = GetWindowTextW( hwnd2, bufW, sizeof(bufW)/sizeof(WCHAR) );
+    ok( buf_len == 0, "got %d\n", buf_len );
+    ok( *bufW == 0, "got %x\n", *bufW );
+    ok( num_gettext_msgs == 1, "got %u WM_GETTEXT messages\n", num_gettext_msgs );
+
+    num_gettext_msgs = 0;
+    memset( bufW, 0xcc, sizeof(bufW) );
+    g_wm_gettext_override.buffW = bufW;
+    buf_len = GetWindowTextW( hwnd2, bufW, 0 );
+    ok( buf_len == 0, "got %d\n", buf_len );
+    ok( *bufW == 0xcccc, "got %x\n", *bufW );
+    ok( num_gettext_msgs == 0, "got %u WM_GETTEXT messages\n", num_gettext_msgs );
+
+    g_wm_gettext_override.enabled = FALSE;
+
+    DestroyWindow( hwnd2 );
+
     /* test WM_GETTEXT */
     num_gettext_msgs = 0;
     memset( buf, 0, sizeof(buf) );
@@ -5858,7 +6577,7 @@ static void test_GetUpdateRect(void)
     flush_events( TRUE );
 
     ShowWindow(hchild, SW_HIDE);
-    SetRect(&rc2, 0, 0, 0, 0);
+    SetRectEmpty(&rc2);
     ret = GetUpdateRect(hgrandparent, &rc1, FALSE);
     ok(!ret, "GetUpdateRect returned not empty region\n");
     ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d,%d,%d) / (%d,%d,%d,%d)\n",
@@ -5922,7 +6641,7 @@ static void test_GetUpdateRect(void)
 
     ShowWindow(hchild, SW_HIDE);
 
-    SetRect(&rc2, 0, 0, 0, 0);
+    SetRectEmpty(&rc2);
     ret = GetUpdateRect(hgrandparent, &rc1, FALSE);
     ok(!ret, "GetUpdateRect returned not empty region\n");
     ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d,%d,%d) / (%d,%d,%d,%d)\n",
@@ -6047,9 +6766,7 @@ static void run_NCRedrawLoop(UINT flags)
         DispatchMessageA(&msg);
         MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT);
     }
-    if (flags == (RDW_INVALIDATE | RDW_FRAME))
-        todo_wine ok(loopcount < 100, "Detected infinite WM_PAINT loop (%x).\n", flags);
-    else
+    todo_wine_if (flags == (RDW_INVALIDATE | RDW_FRAME))
         ok(loopcount < 100, "Detected infinite WM_PAINT loop (%x).\n", flags);
     DestroyWindow(hwnd);
 }
@@ -6324,10 +7041,12 @@ static void test_layered_window(void)
         ret = pUpdateLayeredWindowIndirect( hwnd, &info );
         ok( ret, "UpdateLayeredWindowIndirect should succeed on layered window\n" );
         sz.cx--;
+        SetLastError(0);
         ret = pUpdateLayeredWindowIndirect( hwnd, &info );
         ok( !ret, "UpdateLayeredWindowIndirect should fail\n" );
-        ok( GetLastError() == ERROR_INCORRECT_SIZE || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND),
-            "wrong error %u\n", GetLastError() );
+        /* particular error code differs from version to version, could be ERROR_INCORRECT_SIZE,
+           ERROR_MR_MID_NOT_FOUND or ERROR_GEN_FAILURE (Win8/Win10) */
+        ok( GetLastError() != 0, "wrong error %u\n", GetLastError() );
         info.dwFlags  = ULW_OPAQUE;
         ret = pUpdateLayeredWindowIndirect( hwnd, &info );
         ok( ret, "UpdateLayeredWindowIndirect should succeed on layered window\n" );
@@ -6541,11 +7260,11 @@ static void test_fullscreen(void)
             /* Windows makes a maximized window slightly larger (to hide the borders?) */
             fixup = min(abs(rc.left), abs(rc.top));
             InflateRect(&rc, -fixup, -fixup);
-            ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top &&
-               rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom,
+            ok(rc.left >= mi.rcMonitor.left && rc.top >= mi.rcMonitor.top &&
+               rc.right <= mi.rcMonitor.right && rc.bottom <= mi.rcMonitor.bottom,
                "%#x/%#x: window rect %d,%d-%d,%d must be in %d,%d-%d,%d\n",
                ex_style, style, rc.left, rc.top, rc.right, rc.bottom,
-               mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom);
+               mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom);
             DestroyWindow(hwnd);
 
             style = t_style[i] | WS_MAXIMIZE | WS_MAXIMIZEBOX;
@@ -6563,8 +7282,8 @@ static void test_fullscreen(void)
                    rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom,
                    "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom);
             else
-                ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top &&
-                   rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom,
+                ok(rc.left >= mi.rcMonitor.left && rc.top >= mi.rcMonitor.top &&
+                   rc.right <= mi.rcMonitor.right && rc.bottom <= mi.rcMonitor.bottom,
                    "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom);
             DestroyWindow(hwnd);
         }
@@ -6871,7 +7590,7 @@ static void test_winregion(void)
         ok( ret == ERROR, "Expected ERROR, got %d\n", ret);
         ok( GetLastError() == 0xdeadbeef, "Expected , got %d\n", GetLastError());
 
-        r.left = r.top = r.right = r.bottom = 0;
+        SetRectEmpty(&r);
         ret = pGetWindowRgnBox(hwnd, &r);
         ok( ret == SIMPLEREGION, "Expected SIMPLEREGION, got %d\n", ret);
         ok( r.left == 2 && r.top == 3 && r.right == 10 && r.bottom == 15,
@@ -6882,10 +7601,10 @@ static void test_winregion(void)
             hrgn = CreateRectRgn(2, 3, 10, 15);
             ret = pMirrorRgn( hwnd, hrgn );
             ok( ret == TRUE, "MirrorRgn failed %u\n", ret );
-            r.left = r.top = r.right = r.bottom = 0;
+            SetRectEmpty(&r);
             GetWindowRect( hwnd, &r );
             width = r.right - r.left;
-            r.left = r.top = r.right = r.bottom = 0;
+            SetRectEmpty(&r);
             ret = GetRgnBox( hrgn, &r );
             ok( ret == SIMPLEREGION, "GetRgnBox failed %u\n", ret );
             ok( r.left == width - 10 && r.top == 3 && r.right == width - 2 && r.bottom == 15,
@@ -6954,6 +7673,33 @@ static void test_rtl_layout(void)
     DestroyWindow( parent );
 }
 
+static void test_FlashWindow(void)
+{
+    HWND hwnd;
+    BOOL ret;
+    if (!pFlashWindow)
+    {
+        win_skip( "FlashWindow not supported\n" );
+        return;
+    }
+
+    hwnd = CreateWindowExA( 0, "MainWindowClass", "FlashWindow", WS_POPUP,
+                            0, 0, 0, 0, 0, 0, 0, NULL );
+    ok( hwnd != 0, "CreateWindowExA error %d\n", GetLastError() );
+
+    SetLastError( 0xdeadbeef );
+    ret = pFlashWindow( NULL, TRUE );
+    ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "FlashWindow returned with %d\n", GetLastError() );
+
+    DestroyWindow( hwnd );
+
+    SetLastError( 0xdeadbeef );
+    ret = pFlashWindow( hwnd, TRUE );
+    ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "FlashWindow returned with %d\n", GetLastError() );
+}
+
 static void test_FlashWindowEx(void)
 {
     HWND hwnd;
@@ -6977,13 +7723,13 @@ static void test_FlashWindowEx(void)
     finfo.hwnd = NULL;
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(&finfo);
-    todo_wine ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
-                 "FlashWindowEx returned with %d\n", GetLastError());
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+       "FlashWindowEx returned with %d\n", GetLastError());
 
     finfo.hwnd = hwnd;
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(NULL);
-    todo_wine ok(!ret && GetLastError() == ERROR_NOACCESS,
+    ok(!ret && GetLastError() == ERROR_NOACCESS,
        "FlashWindowEx returned with %d\n", GetLastError());
 
     SetLastError(0xdeadbeef);
@@ -6993,13 +7739,13 @@ static void test_FlashWindowEx(void)
     finfo.cbSize = sizeof(FLASHWINFO) - 1;
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(&finfo);
-    todo_wine ok(!ret && GetLastError()==ERROR_INVALID_PARAMETER,
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
        "FlashWindowEx succeeded\n");
 
     finfo.cbSize = sizeof(FLASHWINFO) + 1;
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(&finfo);
-    todo_wine ok(!ret && GetLastError()==ERROR_INVALID_PARAMETER,
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
        "FlashWindowEx succeeded\n");
     finfo.cbSize = sizeof(FLASHWINFO);
 
@@ -7007,7 +7753,7 @@ static void test_FlashWindowEx(void)
 
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(&finfo);
-    todo_wine ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
        "FlashWindowEx returned with %d\n", GetLastError());
 
     ok(finfo.cbSize == sizeof(FLASHWINFO), "FlashWindowEx modified cdSize to %x\n", finfo.cbSize);
@@ -7023,7 +7769,7 @@ static void test_FlashWindowEx(void)
 
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(NULL);
-    todo_wine ok(!ret && GetLastError() == ERROR_NOACCESS,
+    ok(!ret && GetLastError() == ERROR_NOACCESS,
        "FlashWindowEx returned with %d\n", GetLastError());
 
     SetLastError(0xdeadbeef);
@@ -7038,7 +7784,6 @@ static void test_FlashWindowEx(void)
     finfo.dwFlags = FLASHW_STOP;
     SetLastError(0xdeadbeef);
     ret = pFlashWindowEx(&finfo);
-todo_wine
     ok(prev != ret, "previous window state should be different\n");
 
     DestroyWindow( hwnd );
@@ -7298,9 +8043,7 @@ static void test_child_window_from_point(void)
         ok(hwnd != 0, "RealChildWindowFromPoint failed\n");
         ret = window_to_index(hwnd, window, sizeof(window)/sizeof(window[0]));
         /* FIXME: remove once Wine is fixed */
-        if (ret != real_child_pos[i])
-            todo_wine ok(ret == real_child_pos[i] || broken(ret == real_child_pos_nt4[i]), "expected %d, got %d\n", real_child_pos[i], ret);
-        else
+        todo_wine_if (ret != real_child_pos[i])
             ok(ret == real_child_pos[i] || broken(ret == real_child_pos_nt4[i]), "expected %d, got %d\n", real_child_pos[i], ret);
 
         get_window_attributes(hwnd, &attrs);
@@ -8044,6 +8787,404 @@ static void test_GetMessagePos(void)
     DestroyWindow(button);
 }
 
+#define SET_FOREGROUND_STEAL_1          0x01
+#define SET_FOREGROUND_SET_1            0x02
+#define SET_FOREGROUND_STEAL_2          0x04
+#define SET_FOREGROUND_SET_2            0x08
+#define SET_FOREGROUND_INJECT           0x10
+
+struct set_foreground_thread_params
+{
+    UINT msg_quit, msg_command;
+    HWND window1, window2, thread_window;
+    HANDLE command_executed;
+};
+
+static DWORD WINAPI set_foreground_thread(void *params)
+{
+    struct set_foreground_thread_params *p = params;
+    MSG msg;
+
+    p->thread_window = CreateWindowExA(0, "static", "thread window", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            0, 0, 10, 10, 0, 0, 0, NULL);
+    SetEvent(p->command_executed);
+
+    while(GetMessageA(&msg, 0, 0, 0))
+    {
+        if (msg.message == p->msg_quit)
+            break;
+
+        if (msg.message == p->msg_command)
+        {
+            if (msg.wParam & SET_FOREGROUND_STEAL_1)
+            {
+                SetForegroundWindow(p->thread_window);
+                check_wnd_state(p->thread_window, p->thread_window, p->thread_window, 0);
+            }
+            if (msg.wParam & SET_FOREGROUND_INJECT)
+            {
+                SendNotifyMessageA(p->window1, WM_ACTIVATEAPP, 0, 0);
+            }
+            if (msg.wParam & SET_FOREGROUND_SET_1)
+            {
+                SetForegroundWindow(p->window1);
+                check_wnd_state(0, p->window1, 0, 0);
+            }
+            if (msg.wParam & SET_FOREGROUND_STEAL_2)
+            {
+                SetForegroundWindow(p->thread_window);
+                check_wnd_state(p->thread_window, p->thread_window, p->thread_window, 0);
+            }
+            if (msg.wParam & SET_FOREGROUND_SET_2)
+            {
+                SetForegroundWindow(p->window2);
+                check_wnd_state(0, p->window2, 0, 0);
+            }
+
+            SetEvent(p->command_executed);
+            continue;
+        }
+
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+
+    DestroyWindow(p->thread_window);
+    return 0;
+}
+
+static void test_activateapp(HWND window1)
+{
+    HWND window2, test_window;
+    HANDLE thread;
+    struct set_foreground_thread_params thread_params;
+    DWORD tid;
+    MSG msg;
+
+    window2 = CreateWindowExA(0, "static", "window 2", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            300, 0, 10, 10, 0, 0, 0, NULL);
+    thread_params.msg_quit = WM_USER;
+    thread_params.msg_command = WM_USER + 1;
+    thread_params.window1 = window1;
+    thread_params.window2 = window2;
+    thread_params.command_executed = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    thread = CreateThread(NULL, 0, set_foreground_thread, &thread_params, 0, &tid);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+
+    SetForegroundWindow(window1);
+    check_wnd_state(window1, window1, window1, 0);
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+
+    /* Steal foreground: WM_ACTIVATEAPP(0) is delivered. */
+    app_activated = app_deactivated = FALSE;
+    PostThreadMessageA(tid, thread_params.msg_command, SET_FOREGROUND_STEAL_1, 0);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+    test_window = GetForegroundWindow();
+    ok(test_window == thread_params.thread_window, "Expected foreground window %p, got %p\n",
+            thread_params.thread_window, test_window);
+    /* Active and Focus window are sometimes 0 on KDE. Ignore them.
+     * check_wnd_state(window1, thread_params.thread_window, window1, 0); */
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    check_wnd_state(0, thread_params.thread_window, 0, 0);
+    test_window = GetForegroundWindow();
+    ok(test_window == thread_params.thread_window, "Expected foreground window %p, got %p\n",
+            thread_params.thread_window, test_window);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    /* This message is reliable on Windows and inside a virtual desktop.
+     * It is unreliable on KDE (50/50) and never arrives on FVWM.
+     * ok(app_deactivated, "Expected WM_ACTIVATEAPP(0), did not receive it.\n"); */
+
+    /* Set foreground: WM_ACTIVATEAPP (1) is delivered. */
+    app_activated = app_deactivated = FALSE;
+    PostThreadMessageA(tid, thread_params.msg_command, SET_FOREGROUND_SET_1, 0);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+    check_wnd_state(0, 0, 0, 0);
+    test_window = GetForegroundWindow();
+    ok(!test_window, "Expected foreground window 0, got %p\n", test_window);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(!= 0), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    check_wnd_state(window1, window1, window1, 0);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    ok(app_activated, "Expected WM_ACTIVATEAPP(1), did not receive it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+
+    /* Steal foreground then set it back: No messages are delivered. */
+    app_activated = app_deactivated = FALSE;
+    PostThreadMessageA(tid, thread_params.msg_command, SET_FOREGROUND_STEAL_1 | SET_FOREGROUND_SET_1, 0);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    check_wnd_state(window1, window1, window1, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    check_wnd_state(window1, window1, window1, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+
+    /* This is not implemented with a plain WM_ACTIVATEAPP filter. */
+    app_activated = app_deactivated = FALSE;
+    PostThreadMessageA(tid, thread_params.msg_command, SET_FOREGROUND_STEAL_1
+            | SET_FOREGROUND_INJECT | SET_FOREGROUND_SET_1, 0);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    check_wnd_state(window1, window1, window1, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    check_wnd_state(window1, window1, window1, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(app_deactivated, "Expected WM_ACTIVATEAPP(0), did not receive it.\n");
+
+    SetForegroundWindow(thread_params.thread_window);
+
+    /* Set foreground then remove: Both messages are delivered. */
+    app_activated = app_deactivated = FALSE;
+    PostThreadMessageA(tid, thread_params.msg_command, SET_FOREGROUND_SET_1 | SET_FOREGROUND_STEAL_2, 0);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+    test_window = GetForegroundWindow();
+    ok(test_window == thread_params.thread_window, "Expected foreground window %p, got %p\n",
+            thread_params.thread_window, test_window);
+    check_wnd_state(0, thread_params.thread_window, 0, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    test_window = GetForegroundWindow();
+    ok(test_window == thread_params.thread_window, "Expected foreground window %p, got %p\n",
+            thread_params.thread_window, test_window);
+    /* Active and focus are window1 on wine because the internal WM_WINE_SETACTIVEWINDOW(0)
+     * message is never generated. GetCapture() returns 0 though, so we'd get a test success
+     * in todo_wine in the line below.
+     * todo_wine check_wnd_state(0, thread_params.thread_window, 0, 0); */
+    ok(app_activated, "Expected WM_ACTIVATEAPP(1), did not receive it.\n");
+    todo_wine ok(app_deactivated, "Expected WM_ACTIVATEAPP(0), did not receive it.\n");
+
+    SetForegroundWindow(window1);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    check_wnd_state(window1, window1, window1, 0);
+
+    /* Switch to a different window from the same thread? No messages. */
+    app_activated = app_deactivated = FALSE;
+    PostThreadMessageA(tid, thread_params.msg_command, SET_FOREGROUND_STEAL_1 | SET_FOREGROUND_SET_2, 0);
+    WaitForSingleObject(thread_params.command_executed, INFINITE);
+    test_window = GetForegroundWindow();
+    ok(test_window == window1, "Expected foreground window %p, got %p\n",
+            window1, test_window);
+    check_wnd_state(window1, window1, window1, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    test_window = GetForegroundWindow();
+    ok(test_window == window2, "Expected foreground window %p, got %p\n",
+            window2, test_window);
+    check_wnd_state(window2, window2, window2, 0);
+    ok(!app_activated, "Received WM_ACTIVATEAPP(1), did not expect it.\n");
+    ok(!app_deactivated, "Received WM_ACTIVATEAPP(0), did not expect it.\n");
+
+    PostThreadMessageA(tid, thread_params.msg_quit, 0, 0);
+    WaitForSingleObject(thread, INFINITE);
+
+    CloseHandle(thread_params.command_executed);
+    DestroyWindow(window2);
+}
+
+static LRESULT WINAPI winproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if(!hwnd) {
+        int *count = (int*)lparam;
+        (*count)++;
+    }
+    return 0;
+}
+
+static LRESULT WINAPI winproc_convA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if(msg == WM_SETTEXT)
+    {
+        const char *text = (const char*)lparam;
+
+        ok(!wparam, "wparam = %08lx\n", wparam);
+        ok(!strcmp(text, "text"), "WM_SETTEXT lparam = %s\n", text);
+        return 1;
+    }
+    return 0;
+}
+
+static const WCHAR textW[] = {'t','e','x','t',0};
+static LRESULT WINAPI winproc_convW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    if(msg == WM_SETTEXT)
+    {
+        const WCHAR *text = (const WCHAR*)lparam;
+
+        ok(!wparam, "wparam = %08lx\n", wparam);
+        ok(!lstrcmpW(text, textW), "WM_SETTEXT lparam = %s\n", wine_dbgstr_w(text));
+        return 1;
+    }
+    return 0;
+}
+
+static void test_winproc_handles(const char *argv0)
+{
+    static const WCHAR winproc_testW[] = {'w','i','n','p','r','o','c','_','t','e','s','t',0};
+
+    HINSTANCE hinst = GetModuleHandleA(NULL);
+    WNDCLASSA wnd_classA;
+    WNDCLASSW wnd_classW;
+    int count, ret;
+    PROCESS_INFORMATION info;
+    STARTUPINFOA startup;
+    char cmd[MAX_PATH];
+
+    memset(&wnd_classA, 0, sizeof(wnd_classA));
+    wnd_classA.lpszClassName = "winproc_test";
+    wnd_classA.lpfnWndProc = winproc;
+    ret = RegisterClassA(&wnd_classA);
+    ok(ret, "RegisterClass failed with error %d\n", GetLastError());
+
+    ret = GetClassInfoW(hinst, winproc_testW, &wnd_classW);
+    ok(ret, "GetClassInfoW failed with error %d\n", GetLastError());
+    ok(wnd_classA.lpfnWndProc != wnd_classW.lpfnWndProc,
+            "winproc pointers should not be identical\n");
+
+    count = 0;
+    CallWindowProcA(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count);
+    ok(count == 1, "winproc should be called once (%d)\n", count);
+    count = 0;
+    CallWindowProcW(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count);
+    ok(count == 1, "winproc should be called once (%d)\n", count);
+
+    ret = UnregisterClassW(winproc_testW, hinst);
+    ok(ret, "UnregisterClass failed with error %d\n", GetLastError());
+
+    /* crashes on 64-bit windows because lpfnWndProc handle is already freed */
+    if (sizeof(void*) == 4)
+    {
+        count = 0;
+        CallWindowProcA(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count);
+        todo_wine ok(!count, "winproc should not be called (%d)\n", count);
+        CallWindowProcW(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count);
+        todo_wine ok(!count, "winproc should not be called (%d)\n", count);
+    }
+
+    sprintf(cmd, "%s win winproc_limit", argv0);
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    ok(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL,
+                &startup, &info), "CreateProcess failed.\n");
+    winetest_wait_child_process(info.hProcess);
+    CloseHandle(info.hProcess);
+    CloseHandle(info.hThread);
+}
+
+static void test_winproc_limit(void)
+{
+    WNDPROC winproc_handle;
+    LONG_PTR ret;
+    HWND hwnd;
+    int i;
+
+    hwnd = CreateWindowExA(0, "static", "test", WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
+    ok(hwnd != 0, "CreateWindowEx failed\n");
+
+    ok(SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc),
+            "SetWindowLongPtr failed\n");
+    winproc_handle = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
+    ok(winproc_handle != winproc, "winproc pointers should not be identical\n");
+
+    /* run out of winproc slots */
+    for(i = 2; i<0xffff; i++)
+    {
+        ok(SetWindowLongPtrA(hwnd, GWLP_WNDPROC, i), "SetWindowLongPtr failed (%d)\n", i);
+        if(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == i)
+            break;
+    }
+    ok(i != 0xffff, "unable to run out of winproc slots\n");
+
+    ret = SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc_convA);
+    ok(ret, "SetWindowLongPtr failed with error %d\n", GetLastError());
+    ok(SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"text"), "WM_SETTEXT failed\n");
+    ok(SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW), "WM_SETTEXT with conversion failed\n");
+
+    ret = SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc_convW);
+    ok(ret, "SetWindowLongPtr failed with error %d\n", GetLastError());
+    ok(SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"text"), "WM_SETTEXT failed\n");
+    ok(SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW), "WM_SETTEXT with conversion failed\n");
+
+    /* Show that there's no message conversion when CallWindowProc is used */
+    ok(CallWindowProcA(winproc_convW, hwnd, WM_SETTEXT, 0, (LPARAM)textW) == 1,
+            "winproc_convW returned error\n");
+    ok(CallWindowProcW(winproc_convW, hwnd, WM_SETTEXT, 0, (LPARAM)textW) == 1,
+            "winproc_convW returned error\n");
+
+    i = 0;
+    CallWindowProcA(winproc_handle, 0, 0, 0, (LPARAM)&i);
+    ok(i == 1, "winproc should be called once (%d)\n", i);
+    i = 0;
+    CallWindowProcW(winproc_handle, 0, 0, 0, (LPARAM)&i);
+    ok(i == 1, "winproc should be called once (%d)\n", i);
+
+    DestroyWindow(hwnd);
+
+    i = 0;
+    CallWindowProcA(winproc_handle, 0, 0, 0, (LPARAM)&i);
+    ok(i == 1, "winproc should be called once (%d)\n", i);
+    i = 0;
+    CallWindowProcW(winproc_handle, 0, 0, 0, (LPARAM)&i);
+    ok(i == 1, "winproc should be called once (%d)\n", i);
+}
+
+static void test_deferwindowpos(void)
+{
+    HDWP hdwp, hdwp2;
+    BOOL ret;
+
+    hdwp = BeginDeferWindowPos(0);
+    ok(hdwp != NULL, "got %p\n", hdwp);
+
+    ret = EndDeferWindowPos(NULL);
+    ok(!ret, "got %d\n", ret);
+
+    hdwp2 = DeferWindowPos(NULL, NULL, NULL, 0, 0, 10, 10, 0);
+todo_wine
+    ok(hdwp2 == NULL && ((GetLastError() == ERROR_INVALID_DWP_HANDLE) ||
+        broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %d\n", hdwp2, GetLastError());
+
+    hdwp2 = DeferWindowPos((HDWP)0xdead, GetDesktopWindow(), NULL, 0, 0, 10, 10, 0);
+todo_wine
+    ok(hdwp2 == NULL && ((GetLastError() == ERROR_INVALID_DWP_HANDLE) ||
+        broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %d\n", hdwp2, GetLastError());
+
+    hdwp2 = DeferWindowPos(hdwp, NULL, NULL, 0, 0, 10, 10, 0);
+    ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError());
+
+    hdwp2 = DeferWindowPos(hdwp, GetDesktopWindow(), NULL, 0, 0, 10, 10, 0);
+    ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError());
+
+    hdwp2 = DeferWindowPos(hdwp, (HWND)0xdead, NULL, 0, 0, 10, 10, 0);
+    ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError());
+
+    ret = EndDeferWindowPos(hdwp);
+    ok(ret, "got %d\n", ret);
+}
+
 START_TEST(win)
 {
     char **argv;
@@ -8063,6 +9204,7 @@ START_TEST(win)
     pGetGUIThreadInfo = (void *)GetProcAddress( user32, "GetGUIThreadInfo" );
     pGetProcessDefaultLayout = (void *)GetProcAddress( user32, "GetProcessDefaultLayout" );
     pSetProcessDefaultLayout = (void *)GetProcAddress( user32, "SetProcessDefaultLayout" );
+    pFlashWindow = (void *)GetProcAddress( user32, "FlashWindow" );
     pFlashWindowEx = (void *)GetProcAddress( user32, "FlashWindowEx" );
     pGetLayout = (void *)GetProcAddress( gdi32, "GetLayout" );
     pSetLayout = (void *)GetProcAddress( gdi32, "SetLayout" );
@@ -8077,6 +9219,12 @@ START_TEST(win)
         return;
     }
 
+    if (argc==3 && !strcmp(argv[2], "winproc_limit"))
+    {
+        test_winproc_limit();
+        return;
+    }
+
     if (!RegisterWindowClasses()) assert(0);
 
     hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
@@ -8126,6 +9274,7 @@ START_TEST(win)
     test_capture_3(hwndMain, hwndMain2);
     test_capture_4();
     test_rtl_layout();
+    test_FlashWindow();
     test_FlashWindowEx();
 
     test_CreateWindow();
@@ -8158,6 +9307,7 @@ START_TEST(win)
     test_AdjustWindowRect();
     test_window_styles();
     test_dialog_styles();
+    test_dialog_parent();
     test_redrawnow();
     test_csparentdc();
     test_SetWindowLong();
@@ -8177,6 +9327,13 @@ START_TEST(win)
     test_smresult();
     test_GetMessagePos();
 
+    if (!winetest_interactive)
+        skip("ROSTESTS-208: Skipping test_activateapp(hwndMain).\n");
+    else
+        test_activateapp(hwndMain);
+    test_winproc_handles(argv[0]);
+    test_deferwindowpos();
+
     /* add the tests above this line */
     if (hhook) UnhookWindowsHookEx(hhook);