[USER32_WINETEST] Sync with Wine Staging 1.7.55 except clipboard tests. CORE-10536
authorAmine Khaldi <amine.khaldi@reactos.org>
Tue, 8 Dec 2015 10:22:43 +0000 (10:22 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Tue, 8 Dec 2015 10:22:43 +0000 (10:22 +0000)
svn path=/trunk/; revision=70293

rostests/winetests/user32/cursoricon.c
rostests/winetests/user32/menu.c
rostests/winetests/user32/monitor.c
rostests/winetests/user32/msg.c
rostests/winetests/user32/sysparams.c
rostests/winetests/user32/win.c

index 54d7963..4b6b792 100644 (file)
@@ -308,21 +308,33 @@ static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
 
 static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    BOOL ret;
-    DWORD error;
-
     switch (msg)
     {
         /* Destroy the cursor. */
         case WM_USER+1:
+        {
+            HCURSOR cursor = (HCURSOR)lParam;
+            ICONINFO info;
+            BOOL ret;
+            DWORD error;
+
+            memset(&info, 0, sizeof(info));
+            ret = GetIconInfo(cursor, &info);
+            todo_wine ok(ret, "GetIconInfoEx failed with error %u\n", GetLastError());
+            todo_wine ok(info.hbmColor != NULL, "info.hmbColor was not set\n");
+            todo_wine ok(info.hbmMask != NULL, "info.hmbColor was not set\n");
+            DeleteObject(info.hbmColor);
+            DeleteObject(info.hbmMask);
+
             SetLastError(0xdeadbeef);
-            ret = DestroyCursor((HCURSOR) lParam);
+            ret = DestroyCursor(cursor);
             error = GetLastError();
             ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
             ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD ||
                error == 0xdeadbeef,  /* vista */
                 "Last error: %u\n", error);
             return TRUE;
+        }
         case WM_DESTROY:
             PostQuitMessage(0);
             return 0;
index cc3b6d0..847bf83 100755 (executable)
@@ -2508,9 +2508,10 @@ static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type,
         mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU;
         ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
-if (0)
-        trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
-               i, mii.fType, mii.fState, mii.wID, mii.hSubMenu);
+
+        if (winetest_debug > 1)
+            trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n",
+                  i, mii.fType, mii.fState, mii.wID, mii.hSubMenu);
 
         if (mii.hSubMenu)
         {
@@ -2672,9 +2673,9 @@ static void test_menu_resource_layout(void)
         mii.fMask  = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_STRING;
         ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
-if (0)
-        trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
-               i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData);
+        if (winetest_debug > 1)
+            trace("item #%u: fType %04x, fState %04x, wID %u, dwTypeData %s\n",
+                  i, mii.fType, mii.fState, mii.wID, (LPCSTR)mii.dwTypeData);
 
         ok(mii.fType == menu_data[i].type,
            "%u: expected fType %04x, got %04x\n", i, menu_data[i].type, mii.fType);
@@ -2778,9 +2779,10 @@ static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT ite
         mii.fMask  = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_BITMAP;
         ret = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
         ok(ret, "GetMenuItemInfo(%u) failed\n", i);
-if (0)
-        trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
-               i, mii.fType, mii.fState, mii.wID, mii.hbmpItem);
+
+        if (winetest_debug > 1)
+            trace("item #%u: fType %04x, fState %04x, wID %04x, hbmp %p\n",
+                  i, mii.fType, mii.fState, mii.wID, mii.hbmpItem);
 
         ok(mii.fType == item[i].type,
            "%u: expected fType %04x, got %04x\n", i, item[i].type, mii.fType);
index 42ae883..864eb85 100644 (file)
@@ -34,6 +34,7 @@ static BOOL (WINAPI *pGetMonitorInfoW)(HMONITOR,LPMONITORINFO);
 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
 static HMONITOR (WINAPI *pMonitorFromRect)(LPCRECT,DWORD);
 static HMONITOR (WINAPI *pMonitorFromWindow)(HWND,DWORD);
+static LONG (WINAPI *pGetDisplayConfigBufferSizes)(UINT32,UINT32*,UINT32*);
 
 static void init_function_pointers(void)
 {
@@ -48,6 +49,7 @@ static void init_function_pointers(void)
     GET_PROC(ChangeDisplaySettingsExW)
     GET_PROC(EnumDisplayDevicesA)
     GET_PROC(EnumDisplayMonitors)
+    GET_PROC(GetDisplayConfigBufferSizes)
     GET_PROC(GetMonitorInfoA)
     GET_PROC(GetMonitorInfoW)
     GET_PROC(MonitorFromPoint)
@@ -543,6 +545,58 @@ static void test_work_area(void)
     DestroyWindow(hwnd);
 }
 
+static void test_display_config(void)
+{
+    UINT32 paths, modes;
+    LONG ret;
+
+    if (!pGetDisplayConfigBufferSizes)
+    {
+        win_skip("GetDisplayConfigBufferSizes is not supported\n");
+        return;
+    }
+
+    ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, NULL, NULL);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+
+    paths = 100;
+    ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, NULL);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+    ok(paths == 100, "got %u\n", paths);
+
+    modes = 100;
+    ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, NULL, &modes);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+    ok(modes == 100, "got %u\n", modes);
+
+    paths = modes = 0;
+    ret = pGetDisplayConfigBufferSizes(QDC_ALL_PATHS, &paths, &modes);
+    if (!ret)
+        ok(paths > 0 && modes > 0, "got %u, %u\n", paths, modes);
+    else
+        ok(ret == ERROR_NOT_SUPPORTED, "got %d\n", ret);
+
+    /* Invalid flags, non-zero invalid flags validation is version (or driver?) dependent,
+       it's unreliable to use in tests. */
+    ret = pGetDisplayConfigBufferSizes(0, NULL, NULL);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+
+    paths = 100;
+    ret = pGetDisplayConfigBufferSizes(0, &paths, NULL);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+    ok(paths == 100, "got %u\n", paths);
+
+    modes = 100;
+    ret = pGetDisplayConfigBufferSizes(0, NULL, &modes);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+    ok(modes == 100, "got %u\n", modes);
+
+    paths = modes = 100;
+    ret = pGetDisplayConfigBufferSizes(0, &paths, &modes);
+    ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_NOT_SUPPORTED, "got %d\n", ret);
+    ok(modes == 0 && paths == 0, "got %u, %u\n", modes, paths);
+}
+
 START_TEST(monitor)
 {
     init_function_pointers();
@@ -550,4 +604,5 @@ START_TEST(monitor)
     test_ChangeDisplaySettingsEx();
     test_monitors();
     test_work_area();
+    test_display_config();
 }
index fcb5c4f..1d46985 100755 (executable)
 #define ARCH "x86"
 #elif defined __x86_64__
 #define ARCH "amd64"
+#elif defined __arm__
+#define ARCH "arm"
+#elif defined __aarch64__
+#define ARCH "arm64"
 #else
 #define ARCH "none"
 #endif
@@ -793,6 +797,9 @@ static const struct message WmShowMaxPopupSeq[] = {
     { 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_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
     { WM_ACTIVATEAPP, sent|wparam, 1 },
     { WM_NCACTIVATE, sent },
     { WM_ACTIVATE, sent|wparam, 1 },
@@ -3206,7 +3213,7 @@ static const struct message WmMinimizeMDIchildVisibleSeq[] = {
     { 0 }
 };
 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
-static const struct message WmRestoreMDIchildInisibleSeq[] = {
+static const struct message WmRestoreMDIchildInvisibleSeq[] = {
     { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED  },
     { WM_NCCALCSIZE, sent|wparam, 1 },
@@ -3534,7 +3541,7 @@ static void test_mdi_messages(void)
     ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
 
     ShowWindow(mdi_child2, SW_RESTORE);
-    ok_sequence(WmRestoreMDIchildInisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
+    ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
     flush_sequence();
 
     ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
@@ -5292,6 +5299,21 @@ static const struct message WmLButtonDownSeq[] =
     { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { 0 }
 };
+static const struct message WmLButtonDownStaticSeq[] =
+{
+    { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
+    { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
+    { 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_CTLCOLORSTATIC, sent|defwinproc },
+    { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
+    { WM_CTLCOLORSTATIC, sent|defwinproc },
+    { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+    { 0 }
+};
 static const struct message WmLButtonUpSeq[] =
 {
     { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
@@ -5302,12 +5324,48 @@ static const struct message WmLButtonUpSeq[] =
     { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
     { 0 }
 };
+static const struct message WmLButtonUpStaticSeq[] =
+{
+    { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
+    { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
+    { WM_CTLCOLORSTATIC, sent|defwinproc },
+    { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+    { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
+    { 0 }
+};
+static const struct message WmLButtonUpAutoSeq[] =
+{
+    { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
+    { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
+    { WM_CTLCOLORSTATIC, sent|defwinproc },
+    { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+    { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
+    { BM_SETCHECK, sent|defwinproc },
+    { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
+    { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
+    { 0 }
+};
+static const struct message WmLButtonUpBrokenSeq[] =
+{
+    { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
 static const struct message WmSetFontButtonSeq[] =
 {
     { WM_SETFONT, sent },
     { WM_PAINT, sent },
     { WM_ERASEBKGND, sent|defwinproc|optional },
     { WM_CTLCOLORBTN, sent|defwinproc },
+    { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
+    { 0 }
+};
+static const struct message WmSetFontStaticSeq[] =
+{
+    { WM_SETFONT, sent },
+    { WM_PAINT, sent },
+    { WM_ERASEBKGND, sent|defwinproc|optional },
+    { WM_CTLCOLORSTATIC, sent|defwinproc },
     { 0 }
 };
 static const struct message WmSetStyleButtonSeq[] =
@@ -5468,48 +5526,62 @@ static void test_button_messages(void)
 {
     static const struct
     {
-       DWORD style;
-       DWORD dlg_code;
-       const struct message *setfocus;
-       const struct message *killfocus;
-       const struct message *setstyle;
-       const struct message *setstate;
-       const struct message *clearstate;
-       const struct message *setcheck;
+        DWORD style;
+        DWORD dlg_code;
+        const struct message *setfocus;
+        const struct message *killfocus;
+        const struct message *setstyle;
+        const struct message *setstate;
+        const struct message *clearstate;
+        const struct message *setcheck;
+        const struct message *lbuttondown;
+        const struct message *lbuttonup;
+        const struct message *setfont;
     } button[] = {
-       { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
-         WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
-          WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
-       { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
-         WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
-          WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq },
-       { BS_CHECKBOX, DLGC_BUTTON,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
-       { BS_AUTOCHECKBOX, DLGC_BUTTON,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
-       { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
-       { BS_3STATE, DLGC_BUTTON,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
-       { BS_AUTO3STATE, DLGC_BUTTON,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
-       { BS_GROUPBOX, DLGC_STATIC,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq },
-       { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
-         WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
-          WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq },
-       { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
-         WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
-          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq },
-       { BS_OWNERDRAW, DLGC_BUTTON,
-         WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
-          WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq },
+        { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
+          WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
+          WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
+          WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq },
+        { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
+          WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
+          WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
+          WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq },
+        { BS_CHECKBOX, DLGC_BUTTON,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
+          WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq },
+        { BS_AUTOCHECKBOX, DLGC_BUTTON,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
+          WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq },
+        { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
+          WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq },
+        { BS_3STATE, DLGC_BUTTON,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
+          WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq },
+        { BS_AUTO3STATE, DLGC_BUTTON,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
+          WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq },
+        { BS_GROUPBOX, DLGC_STATIC,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
+          WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq },
+        { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
+          WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
+          WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
+          WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq },
+        { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
+          WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
+          WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
+          NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq },
+        { BS_OWNERDRAW, DLGC_BUTTON,
+          WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
+          WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
+          WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq },
     };
     unsigned int i;
     HWND hwnd, parent;
@@ -5537,12 +5609,13 @@ static void test_button_messages(void)
     {
         MSG msg;
         DWORD style, state;
+        char desc[64];
 
         trace("button style %08x\n", button[i].style);
 
         hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
                                0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
-       ok(hwnd != 0, "Failed to create button window\n");
+        ok(hwnd != 0, "Failed to create button window\n");
 
         style = GetWindowLongA(hwnd, GWL_STYLE);
         style &= ~(WS_CHILD | BS_NOTIFY);
@@ -5552,28 +5625,28 @@ static void test_button_messages(void)
         else
             ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
 
-       dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
-       ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
+        dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
+        ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
 
-       ShowWindow(hwnd, SW_SHOW);
-       UpdateWindow(hwnd);
-       SetFocus(0);
-       flush_events();
-       SetFocus(0);
-       flush_sequence();
+        ShowWindow(hwnd, SW_SHOW);
+        UpdateWindow(hwnd);
+        SetFocus(0);
+        flush_events();
+        SetFocus(0);
+        flush_sequence();
 
         log_all_parent_messages++;
 
         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
-       SetFocus(hwnd);
+        SetFocus(hwnd);
         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].setfocus, "SetFocus(hwnd) on a button", FALSE);
+        ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
 
-       SetFocus(0);
+        SetFocus(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].killfocus, "SetFocus(0) on a button", FALSE);
+        ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
 
         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
 
@@ -5662,39 +5735,45 @@ static void test_button_messages(void)
 
         log_all_parent_messages--;
 
-       DestroyWindow(hwnd);
-    }
+        DestroyWindow(hwnd);
 
-    DestroyWindow(parent);
+        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");
 
-    hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | 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();
 
-    SetForegroundWindow(hwnd);
-    flush_events();
+        SetActiveWindow(hwnd);
+        SetFocus(0);
+        flush_sequence();
 
-    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_LBUTTONDOWN, 0, 0);
-    ok_sequence(WmLButtonDownSeq, "WM_LBUTTONDOWN on a button", FALSE);
+        SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
+        sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
+        ok_sequence(button[i].lbuttonup, desc, FALSE);
 
-    SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
-    ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
+        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);
 
-    flush_sequence();
-    zfont = GetStockObject(SYSTEM_FONT);
-    SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
-    UpdateWindow(hwnd);
-    ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
+        DestroyWindow(hwnd);
+    }
 
-    DestroyWindow(hwnd);
+    DestroyWindow(parent);
 }
 
 /****************** static message test *************************/
-static const struct message WmSetFontStaticSeq[] =
+static const struct message WmSetFontStaticSeq2[] =
 {
     { WM_SETFONT, sent },
     { WM_PAINT, sent|defwinproc|optional },
@@ -5754,7 +5833,7 @@ static void test_static_messages(void)
        const struct message *setfont;
     } static_ctrl[] = {
        { SS_LEFT, DLGC_STATIC,
-         WmSetFontStaticSeq }
+         WmSetFontStaticSeq2 }
     };
     unsigned int i;
     HWND hwnd;
@@ -6571,6 +6650,20 @@ static void test_paint_messages(void)
     RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
     ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
 
+    /* WS_CLIPCHILDREN doesn't exclude children from update region */
+    flush_sequence();
+    RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
+    GetClientRect( hparent, &rect );
+    SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
+    check_update_rgn( hparent, hrgn );
+    flush_events();
+
+    RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
+    GetClientRect( hparent, &rect );
+    SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
+    check_update_rgn( hparent, hrgn );
+    flush_events();
+
     /* test RDW_INTERNALPAINT behavior */
 
     flush_sequence();
@@ -8428,6 +8521,7 @@ static void test_timers(void)
     start = GetTickCount();
     while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
         DispatchMessageA(&msg);
+todo_wine
     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
        || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
@@ -8496,6 +8590,7 @@ static void test_timers_no_wnd(void)
     start = GetTickCount();
     while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
         DispatchMessageA(&msg);
+todo_wine
     ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
        || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
        "did not get expected count for minimum timeout (%d != ~%d).\n",
@@ -9107,6 +9202,54 @@ todo_wine {
        "unexpected error %d\n", GetLastError());
 }
 
+static HWND hook_hwnd;
+static HHOOK recursive_hook;
+static int hook_depth, max_hook_depth;
+
+static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
+{
+    LRESULT res;
+    MSG msg;
+    BOOL b;
+
+    hook_depth++;
+    if(hook_depth > max_hook_depth)
+        max_hook_depth = hook_depth;
+
+    b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
+    ok(b, "PeekMessage failed\n");
+
+    res = CallNextHookEx(recursive_hook, code, w, l);
+
+    hook_depth--;
+    return res;
+}
+
+static void test_recursive_hook(void)
+{
+    MSG msg;
+    BOOL b;
+
+    hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
+    ok(hook_hwnd != NULL, "CreateWindow failed\n");
+
+    recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
+    ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
+
+    PostMessageW(hook_hwnd, WM_USER, 0, 0);
+    PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
+
+    hook_depth = 0;
+    GetMessageW(&msg, hook_hwnd, 0, 0);
+    ok(15 < max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
+    trace("max_hook_depth = %d\n", max_hook_depth);
+
+    b = UnhookWindowsHookEx(recursive_hook);
+    ok(b, "UnhokWindowsHookEx failed\n");
+
+    DestroyWindow(hook_hwnd);
+}
+
 static const struct message ScrollWindowPaint1[] = {
     { WM_PAINT, sent },
     { WM_ERASEBKGND, sent|beginpaint },
@@ -10336,13 +10479,14 @@ static void wait_move_event(HWND hwnd, int x, int y)
 {
     MSG msg;
     DWORD time;
-    BOOL ret, go = FALSE;
+    BOOL ret;
 
     time = GetTickCount();
-    while (GetTickCount() - time < 200 && !go) {
+    while (GetTickCount() - time < 200) {
        ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
-       go  = ret && msg.pt.x > x && msg.pt.y > y;
+        if (ret && msg.pt.x > x && msg.pt.y > y) break;
         if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
+        else Sleep( GetTickCount() - time );
     }
 }
 
@@ -10520,6 +10664,25 @@ static void test_PeekMessage3(void)
     ret = PeekMessageA(&msg, NULL, 0, 0, 0);
     ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
 
+    /* Newer messages are still returned when specifying a message range. */
+
+    SetTimer(hwnd, 1, 0, NULL);
+    while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
+    ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
+    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, 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);
+    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_USER, "msg.message = %u instead of WM_USER\n", msg.message);
+    ret = PeekMessageA(&msg, NULL, 0, 0, 0);
+    ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
+
     /* Also works for posted messages, but the situation is a bit different,
      * because both messages are in the same queue. */
 
@@ -11955,6 +12118,18 @@ static void test_SetForegroundWindow(void)
     DestroyWindow(hwnd);
 }
 
+static DWORD get_input_codepage( void )
+{
+    DWORD cp;
+    int ret;
+    HKL hkl = GetKeyboardLayout( 0 );
+
+    ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
+                          (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
+    if (!ret) cp = CP_ACP;
+    return cp;
+}
+
 static void test_dbcs_wm_char(void)
 {
     BYTE dbch[2];
@@ -11968,6 +12143,7 @@ static void test_dbcs_wm_char(void)
     UINT i, j, k;
     struct message wmCharSeq[2];
     BOOL ret;
+    DWORD cp = get_input_codepage();
 
     if (!pGetCPInfoExA)
     {
@@ -11975,7 +12151,7 @@ static void test_dbcs_wm_char(void)
         return;
     }
 
-    pGetCPInfoExA( CP_ACP, 0, &cpinfo );
+    pGetCPInfoExA( cp, 0, &cpinfo );
     if (cpinfo.MaxCharSize != 2)
     {
         skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
@@ -11993,8 +12169,8 @@ static void test_dbcs_wm_char(void)
                 WCHAR wstr[2];
                 str[0] = j;
                 str[1] = k;
-                if (MultiByteToWideChar( CP_ACP, 0, str, 2, wstr, 2 ) == 1 &&
-                    WideCharToMultiByte( CP_ACP, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
+                if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
+                    WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
                     (BYTE)str[0] == j && (BYTE)str[1] == k &&
                     HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
                 {
@@ -14853,7 +15029,11 @@ START_TEST(msg)
     test_timers();
     test_timers_no_wnd();
     test_timers_exceptions();
-    if (hCBT_hook) test_set_hook();
+    if (hCBT_hook)
+    {
+        test_set_hook();
+        test_recursive_hook();
+    }
     test_DestroyWindow();
     test_DispatchMessage();
     test_SendMessageTimeout();
@@ -15107,7 +15287,11 @@ START_TEST(msg_hook)
         pUnhookWinEvent = 0;
     }
     hEvent_hook = 0;
-    if (hCBT_hook) test_set_hook();
+    if (hCBT_hook)
+    {
+        test_set_hook();
+        test_recursive_hook();
+    }
     cleanup_tests();
 }
 
index 6c3489f..bd0c240 100755 (executable)
@@ -2651,6 +2651,23 @@ static int gsm_error_ctr;
     ok( !( exp1 != act && exp2 != act && exp3 != act),"GetSystemMetrics(%s): expected %d or %d or %d actual %d\n", #i, exp1, exp2, exp3, act);\
 }
 
+static INT CALLBACK enum_all_fonts_proc(const LOGFONTA *elf, const TEXTMETRICA *ntm, DWORD type, LPARAM lparam)
+{
+    return lstrcmpiA(elf->lfFaceName, (const char *)lparam);
+}
+
+static BOOL is_font_enumerated(const char *name)
+{
+    HDC hdc = CreateCompatibleDC(0);
+    BOOL ret = FALSE;
+
+    if (!EnumFontFamiliesA(hdc, NULL, enum_all_fonts_proc, (LPARAM)name))
+        ret = TRUE;
+
+    DeleteDC(hdc);
+    return ret;
+}
+
 static void test_GetSystemMetrics( void)
 {
     TEXTMETRICA tmMenuFont;
@@ -2692,6 +2709,13 @@ static void test_GetSystemMetrics( void)
         win_skip("SPI_GETNONCLIENTMETRICS is not available\n");
         return;
     }
+
+    ok(is_font_enumerated(ncm.lfCaptionFont.lfFaceName), "font %s should be enumerated\n", ncm.lfCaptionFont.lfFaceName);
+    ok(is_font_enumerated(ncm.lfSmCaptionFont.lfFaceName), "font %s should be enumerated\n", ncm.lfSmCaptionFont.lfFaceName);
+    ok(is_font_enumerated(ncm.lfMenuFont.lfFaceName), "font %s should be enumerated\n", ncm.lfMenuFont.lfFaceName);
+    ok(is_font_enumerated(ncm.lfStatusFont.lfFaceName), "font %s should be enumerated\n", ncm.lfStatusFont.lfFaceName);
+    ok(is_font_enumerated(ncm.lfMessageFont.lfFaceName), "font %s should be enumerated\n", ncm.lfMessageFont.lfFaceName);
+
     /* CaptionWidth from the registry may have different value of iCaptionWidth
      * from the non client metrics (observed on WinXP) */
     CaptionWidthfromreg = metricfromreg(
index 7cdbc6f..1188d58 100644 (file)
@@ -57,6 +57,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 +69,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;
@@ -717,6 +719,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 +807,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 +871,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 +891,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;
@@ -1240,7 +1295,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 +1314,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 +1325,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);
+todo_wine
+    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 +1342,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);
+todo_wine
+        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 +1367,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 +1383,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 +1398,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);
+todo_wine
+    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 +1419,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);
+todo_wine
+        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 +1445,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 +1461,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 +1476,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);
+todo_wine
+    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 +1497,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);
+todo_wine
+        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 +1523,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 +1551,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 +1564,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 +1578,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 +1592,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 +1606,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 +1920,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,7 +2000,9 @@ static BOOL mdi_RegisterWindowClasses(void)
 
 static void test_mdi(void)
 {
-    HWND mdi_hwndMain;
+    HWND mdi_hwndMain, mdi_client;
+    CLIENTCREATESTRUCT client_cs;
+    RECT rc;
     /*MSG msg;*/
 
     if (!mdi_RegisterWindowClasses()) assert(0);
@@ -1955,6 +2014,46 @@ 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;
+
+    /* 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))
     {
@@ -5726,11 +5825,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 +5845,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) );
@@ -6324,10 +6486,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" );
@@ -6954,6 +7118,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 +7168,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 +7184,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 +7198,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 +7214,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 +7229,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 );
@@ -8044,6 +8234,224 @@ 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);
+}
+
 START_TEST(win)
 {
     char **argv;
@@ -8063,6 +8471,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" );
@@ -8126,6 +8535,7 @@ START_TEST(win)
     test_capture_3(hwndMain, hwndMain2);
     test_capture_4();
     test_rtl_layout();
+    test_FlashWindow();
     test_FlashWindowEx();
 
     test_CreateWindow();
@@ -8177,6 +8587,11 @@ START_TEST(win)
     test_smresult();
     test_GetMessagePos();
 
+    if (!winetest_interactive)
+        skip("ROSTESTS-208: Skipping test_activateapp(hwndMain).\n");
+    else
+        test_activateapp(hwndMain);
+
     /* add the tests above this line */
     if (hhook) UnhookWindowsHookEx(hhook);