[USER32_WINETEST]
authorAmine Khaldi <amine.khaldi@reactos.org>
Sat, 5 Oct 2013 10:20:53 +0000 (10:20 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sat, 5 Oct 2013 10:20:53 +0000 (10:20 +0000)
* Sync with Wine 1.7.1.
CORE-7469

svn path=/trunk/; revision=60530

rostests/winetests/user32/CMakeLists.txt
rostests/winetests/user32/class.c
rostests/winetests/user32/clipboard.c
rostests/winetests/user32/dce.c
rostests/winetests/user32/dde.c
rostests/winetests/user32/menu.c
rostests/winetests/user32/msg.c
rostests/winetests/user32/testlist.c
rostests/winetests/user32/win.c

index 5d2e420..0d22f12 100644 (file)
@@ -1,7 +1,4 @@
 
-add_definitions(
-    -D__ROS_LONG64__)
-
 list(APPEND SOURCE
     broadcast.c
     class.c
@@ -29,13 +26,9 @@ list(APPEND SOURCE
     wsprintf.c
     testlist.c)
 
-add_executable(user32_winetest
-    ${SOURCE}
-    resource.rc)
-
-target_link_libraries(user32_winetest wine)
+add_executable(user32_winetest ${SOURCE} resource.rc)
 set_module_type(user32_winetest win32cui)
-add_importlibs(user32_winetest user32 gdi32 advapi32 msvcrt kernel32 ntdll)
+add_importlibs(user32_winetest user32 gdi32 advapi32 msvcrt kernel32)
 add_cd_file(TARGET user32_winetest DESTINATION reactos/bin FOR all)
 
 if(NOT MSVC)
index 29b2706..b7332ac 100755 (executable)
@@ -977,6 +977,58 @@ if (0) { /* crashes under XP */
     ok(wcx.lpfnWndProc != NULL, "got null proc\n");
 }
 
+static void test_icons(void)
+{
+    WNDCLASSEXW wcex, ret_wcex;
+    WCHAR cls_name[] = {'I','c','o','n','T','e','s','t','C','l','a','s','s',0};
+    HWND hwnd;
+    HINSTANCE hinst = GetModuleHandleW(0);
+    HICON hsmicon, hsmallnew;
+    ICONINFO icinf;
+
+    memset(&wcex, 0, sizeof wcex);
+    wcex.cbSize        = sizeof wcex;
+    wcex.lpfnWndProc   = ClassTest_WndProc;
+    wcex.hIcon         = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
+    wcex.hInstance     = hinst;
+    wcex.lpszClassName = cls_name;
+    ok(RegisterClassExW(&wcex), "RegisterClassExW returned 0\n");
+    hwnd = CreateWindowExW(0, cls_name, NULL, WS_OVERLAPPEDWINDOW,
+                        0, 0, 0, 0, NULL, NULL, hinst, 0);
+    ok(hwnd != NULL, "Window was not created\n");
+
+    ok(GetClassInfoExW(hinst, cls_name, &ret_wcex), "Class info was not retrieved\n");
+    ok(wcex.hIcon == ret_wcex.hIcon, "Icons don't match\n");
+    ok(ret_wcex.hIconSm != NULL, "hIconSm should be non-zero handle\n");
+
+    hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
+    ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n");
+
+    hsmallnew = CopyImage(wcex.hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
+                                                GetSystemMetrics(SM_CYSMICON), 0);
+    ok(!SetClassLongPtrW(hwnd, GCLP_HICONSM, (LONG_PTR)hsmallnew),
+                    "Previous hIconSm should be zero\n");
+    ok(hsmallnew == (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM),
+                    "Should return explicitly assigned small icon\n");
+    ok(!GetIconInfo(hsmicon, &icinf), "Previous small icon should be destroyed\n");
+
+    SetClassLongPtrW(hwnd, GCLP_HICONSM, 0);
+    hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
+    ok( hsmicon != NULL, "GetClassLong should return non-zero handle\n");
+
+    SetClassLongPtrW(hwnd, GCLP_HICON, 0);
+    ok(!GetClassLongPtrW(hwnd, GCLP_HICONSM), "GetClassLong should return zero handle\n");
+
+    SetClassLongPtrW(hwnd, GCLP_HICON, (LONG_PTR)LoadIconW(NULL, (LPCWSTR)IDI_QUESTION));
+    hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
+    ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n");
+    UnregisterClassW(cls_name, hinst);
+    ok(GetIconInfo(hsmicon, &icinf), "Icon should NOT be destroyed\n");
+
+    DestroyIcon(hsmallnew);
+    DestroyWindow(hwnd);
+}
+
 START_TEST(class)
 {
     HANDLE hInstance = GetModuleHandleA( NULL );
@@ -995,6 +1047,7 @@ START_TEST(class)
     CreateDialogParamTest(hInstance);
     test_styles();
     test_builtinproc();
+    test_icons();
 
     /* this test unregisters the Button class so it should be executed at the end */
     test_instances();
index 655d158..e2e727c 100755 (executable)
@@ -269,6 +269,83 @@ static void test_synthesized(void)
     ok(r, "gle %d\n", GetLastError());
 }
 
+static CRITICAL_SECTION clipboard_cs;
+static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+    switch(msg) {
+    case WM_DRAWCLIPBOARD:
+        EnterCriticalSection(&clipboard_cs);
+        LeaveCriticalSection(&clipboard_cs);
+        break;
+    case WM_USER:
+        PostQuitMessage(0);
+        break;
+    }
+
+    return DefWindowProc(hwnd, msg, wp, lp);
+}
+
+static DWORD WINAPI clipboard_thread(void *param)
+{
+    HWND win = param;
+    BOOL r;
+
+    EnterCriticalSection(&clipboard_cs);
+    SetLastError(0xdeadbeef);
+    SetClipboardViewer(win);
+    ok(GetLastError() == 0xdeadbeef, "GetLastError = %d\n", GetLastError());
+    LeaveCriticalSection(&clipboard_cs);
+
+    r = OpenClipboard(win);
+    ok(r, "OpenClipboard failed: %d\n", GetLastError());
+
+    r = EmptyClipboard();
+    ok(r, "EmptyClipboard failed: %d\n", GetLastError());
+
+    EnterCriticalSection(&clipboard_cs);
+    r = CloseClipboard();
+    ok(r, "CloseClipboard failed: %d\n", GetLastError());
+    LeaveCriticalSection(&clipboard_cs);
+
+    r = PostMessage(win, WM_USER, 0, 0);
+    ok(r, "PostMessage failed: %d\n", GetLastError());
+    return 0;
+}
+
+static void test_messages(void)
+{
+    WNDCLASS cls;
+    HWND win;
+    MSG msg;
+    HANDLE thread;
+    DWORD tid;
+
+    InitializeCriticalSection(&clipboard_cs);
+
+    memset(&cls, 0, sizeof(cls));
+    cls.lpfnWndProc = clipboard_wnd_proc;
+    cls.hInstance = GetModuleHandle(0);
+    cls.lpszClassName = "clipboard_test";
+    RegisterClass(&cls);
+
+    win = CreateWindow("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0);
+    ok(win != NULL, "CreateWindow failed: %d\n", GetLastError());
+
+    thread = CreateThread(NULL, 0, clipboard_thread, (void*)win, 0, &tid);
+    ok(thread != NULL, "CreateThread failed: %d\n", GetLastError());
+
+    while(GetMessage(&msg, NULL, 0, 0)) {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+
+    ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+    CloseHandle(thread);
+
+    UnregisterClass("clipboard_test", GetModuleHandle(0));
+    DeleteCriticalSection(&clipboard_cs);
+}
+
 START_TEST(clipboard)
 {
     SetLastError(0xdeadbeef);
@@ -278,4 +355,5 @@ START_TEST(clipboard)
     test_RegisterClipboardFormatA();
     test_ClipboardOwner();
     test_synthesized();
+    test_messages();
 }
index 1aa548e..f75e6b3 100755 (executable)
@@ -78,7 +78,7 @@ static void test_dc_attributes(void)
         old_hdc = hdcs[0];
         SetROP2( old_hdc, R2_WHITE );
     }
-    while (i >= 0) ReleaseDC( hwnd_cache, hdcs[--i] );
+    while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
 
     for (i = 0; i < 20; i++)
     {
@@ -91,7 +91,7 @@ static void test_dc_attributes(void)
         else
             ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
     }
-    while (i >= 0) ReleaseDC( hwnd_cache, hdcs[--i] );
+    while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
 
     for (i = 0; i < 20; i++)
     {
@@ -107,7 +107,7 @@ static void test_dc_attributes(void)
         else
             ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
     }
-    while (i >= 0) ReleaseDC( hwnd_cache, hdcs[--i] );
+    while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
 
     /* test own DC */
 
index 3ad48f0..e5d5554 100755 (executable)
@@ -143,7 +143,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA
         else
             lstrcpyA(str, "requested data\r\n");
 
-        size = sizeof(DDEDATA) + lstrlenA(str) + 1;
+        size = FIELD_OFFSET(DDEDATA, Value[lstrlenA(str) + 1]);
         hglobal = GlobalAlloc(GMEM_MOVEABLE, size);
         ok(hglobal != NULL, "Expected non-NULL hglobal\n");
 
@@ -314,8 +314,7 @@ static void test_ddeml_client(void)
     {
         str = (LPSTR)DdeAccessData(hdata, &size);
         ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str);
-        ok(size == 19 || broken(size == 28), /* sizes are rounded up on win9x */
-           "Expected 19, got %d\n", size);
+        ok(size == 17, "Expected 17, got %d\n", size);
 
         ret = DdeUnaccessData(hdata);
         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -336,8 +335,7 @@ todo_wine
     {
         str = (LPSTR)DdeAccessData(hdata, &size);
         ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str);
-        ok(size == 19 || broken(size == 28), /* sizes are rounded up on win9x */
-           "Expected 19, got %d\n", size);
+        ok(size == 17, "Expected 17, got %d\n", size);
 
         ret = DdeUnaccessData(hdata);
         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -357,8 +355,7 @@ todo_wine
     {
         str = (LPSTR)DdeAccessData(hdata, &size);
         ok(!lstrcmpA(str, "requested data\r\n"), "Expected 'requested data\\r\\n', got %s\n", str);
-        ok(size == 19 || broken(size == 28), /* sizes are rounded up on win9x */
-           "Expected 19, got %d\n", size);
+        ok(size == 17, "Expected 17, got %d\n", size);
 
         ret = DdeUnaccessData(hdata);
         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -483,8 +480,7 @@ todo_wine
     {
         str = (LPSTR)DdeAccessData(hdata, &size);
         ok(!lstrcmpA(str, "command executed\r\n"), "Expected 'command executed\\r\\n', got %s\n", str);
-        ok(size == 21 || broken(size == 28), /* sizes are rounded up on win9x */
-           "Expected 21, got %d\n", size);
+        ok(size == 19, "Expected 19, got %d\n", size);
 
         ret = DdeUnaccessData(hdata);
         ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
index 27315ed..e8f2d0f 100755 (executable)
@@ -3266,7 +3266,8 @@ static void test_menu_cancelmode(void)
 {
     DWORD ret;
     HWND hwnd, hwndchild;
-    HMENU menu;
+    HMENU menu, menubar;
+    MSG msg;
     if( !pEndMenu) { /* win95 */
         win_skip( "EndMenu is not available\n");
         return;
@@ -3287,7 +3288,8 @@ static void test_menu_cancelmode(void)
     ret = AppendMenuA( menu, MF_STRING, 1, "winetest");
     ok( ret, "Functie failed lasterror is %u\n", GetLastError());
     /* seems to be needed only on wine :( */
-    {MSG msg;   while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);}
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+        DispatchMessage(&msg);
     /* test the effect of sending a WM_CANCELMODE message in the WM_INITMENULOOP
      * handler of the menu owner */
     /* test results is extracted from variable g_got_enteridle. Possible values:
@@ -3314,7 +3316,27 @@ static void test_menu_cancelmode(void)
     g_hwndtosend = hwnd;
     TrackPopupMenu( menu, TPM_RETURNCMD, 100,100, 0, hwndchild, NULL);
     ok( g_got_enteridle == 2, "received %d WM_ENTERIDLE messages, should be 2\n", g_got_enteridle);
+
+    /* test canceling tracking in a window's menu bar */
+    menubar = CreateMenu();
+    ok( menubar != NULL, "CreateMenu failed with error %d\n", GetLastError());
+    ret = AppendMenuA( menubar, MF_POPUP|MF_STRING, (UINT_PTR)menu, "winetest");
+    ok( ret, "AppendMenuA failed lasterror is %u\n", GetLastError());
+    ret = SetMenu( hwnd, menubar );
+    ok( ret, "SetMenu failed lasterror is %u\n", GetLastError());
+    /* initiate tracking */
+    g_hwndtosend = hwnd;
+    ret = SendMessage( hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0 );
+    ok( ret == 0, "Sending WM_SYSCOMMAND/SC_KEYMENU failed lasterror is %u\n", GetLastError());
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+        DispatchMessage(&msg);
+    todo_wine {
+        ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle);
+    }
+    ok(g_got_enteridle < 2, "received %d WM_ENTERIDLE messages, should be less than 2\n", g_got_enteridle);
+
     /* cleanup */
+    DestroyMenu( menubar );
     DestroyMenu( menu);
     DestroyWindow( hwndchild);
     DestroyWindow( hwnd);
index 3eb943a..89902ee 100755 (executable)
@@ -1722,6 +1722,8 @@ static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
+static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
+static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
 /* kernel32 functions */
 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
 
@@ -1746,6 +1748,8 @@ static void init_procs(void)
     GET_PROC(user32, GetMonitorInfoA)
     GET_PROC(user32, MonitorFromPoint)
     GET_PROC(user32, UpdateLayeredWindow)
+    GET_PROC(user32, SetSystemTimer)
+    GET_PROC(user32, KillSystemTimer)
 
     GET_PROC(kernel32, GetCPInfoExA)
 
@@ -8156,7 +8160,15 @@ static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
 {
 }
 
-#define TIMER_ID  0x19
+#define TIMER_ID               0x19
+#define TIMER_COUNT_EXPECTED   64
+#define TIMER_COUNT_TOLERANCE  9
+
+static int count = 0;
+static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+    count++;
+}
 
 static DWORD WINAPI timer_thread_proc(LPVOID x)
 {
@@ -8176,7 +8188,9 @@ static DWORD WINAPI timer_thread_proc(LPVOID x)
 static void test_timers(void)
 {
     struct timer_info info;
+    DWORD start;
     DWORD id;
+    MSG msg;
 
     info.hWnd = CreateWindow ("TestWindowClass", NULL,
        WS_OVERLAPPEDWINDOW ,
@@ -8198,23 +8212,53 @@ static void test_timers(void)
 
     ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
 
-    ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
-}
+    /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
+     * but testing indicates that the minimum timeout is actually about 15.6 ms.  Since there is
+     * some measurement error between test runs we're allowing for ±8 counts (~2 ms).
+     */
+    count = 0;
+    id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
+    ok(id != 0, "did not get id from SetTimer.\n");
+    ok(id==TIMER_ID, "SetTimer timer ID different\n");
+    start = GetTickCount();
+    while (GetTickCount()-start < 1001 && GetMessage(&msg, info.hWnd, 0, 0))
+        DispatchMessage(&msg);
+    ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
+       || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3 */,
+       "did not get expected count for minimum timeout (%d != ~%d).\n",
+       count, TIMER_COUNT_EXPECTED);
+    ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
+    /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
+    if (pSetSystemTimer)
+    {
+        int syscount = 0;
+
+        count = 0;
+        id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
+        ok(id != 0, "did not get id from SetSystemTimer.\n");
+        ok(id==TIMER_ID, "SetTimer timer ID different\n");
+        start = GetTickCount();
+        while (GetTickCount()-start < 1001 && GetMessage(&msg, info.hWnd, 0, 0))
+        {
+            if (msg.message == WM_SYSTIMER)
+                syscount++;
+            DispatchMessage(&msg);
+        }
+        ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE,
+           "did not get expected count for minimum timeout (%d != ~%d).\n",
+           syscount, TIMER_COUNT_EXPECTED);
+        todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
+                                 count);
+        ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
+    }
 
-static int count = 0;
-static VOID CALLBACK callback_count(
-    HWND hwnd,
-    UINT uMsg,
-    UINT_PTR idEvent,
-    DWORD dwTime
-)
-{
-    count++;
+    ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
 }
 
 static void test_timers_no_wnd(void)
 {
     UINT_PTR id, id2;
+    DWORD start;
     MSG msg;
 
     count = 0;
@@ -8232,6 +8276,22 @@ static void test_timers_no_wnd(void)
     Sleep(250);
     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
     ok(count == 1, "killing replaced timer did not work (%i).\n", count);
+
+    /* Check the minimum allowed timeout for a timer.  MSDN indicates that it should be 10.0 ms,
+     * but testing indicates that the minimum timeout is actually about 15.6 ms.  Since there is
+     * some measurement error between test runs we're allowing for ±8 counts (~2 ms).
+     */
+    count = 0;
+    id = SetTimer(NULL, 0, 0, callback_count);
+    ok(id != 0, "did not get id from SetTimer.\n");
+    start = GetTickCount();
+    while (GetTickCount()-start < 1001 && GetMessage(&msg, NULL, 0, 0))
+        DispatchMessage(&msg);
+    ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE,
+       "did not get expected count for minimum timeout (%d != ~%d).\n",
+       count, TIMER_COUNT_EXPECTED);
+    KillTimer(NULL, id);
+    /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
 }
 
 /* Various win events with arbitrary parameters */
@@ -9093,6 +9153,26 @@ static void test_DispatchMessage(void)
             if (++count > 10) break;
         }
     }
+
+    flush_sequence();
+    RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
+    count = 0;
+    while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
+    {
+        if (msg.message != WM_PAINT) DispatchMessage( &msg );
+        else
+        {
+            HDC hdc;
+
+            flush_sequence();
+            hdc = BeginPaint( hwnd, NULL );
+            ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
+            ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
+            ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
+            ok( !count, "Got multiple WM_PAINTs\n" );
+            if (++count > 10) break;
+        }
+    }
     DestroyWindow(hwnd);
 }
 
@@ -11820,6 +11900,93 @@ static void test_dbcs_wm_char(void)
     DestroyWindow(hwnd2);
 }
 
+static void test_unicode_wm_char(void)
+{
+    HWND hwnd;
+    MSG msg;
+    struct message seq[2];
+    HKL hkl_orig, hkl_greek;
+    DWORD cp;
+    LCID thread_locale;
+
+    hkl_orig = GetKeyboardLayout( 0 );
+    GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
+    if (cp != 1252)
+    {
+        skip( "Default codepage %d\n", cp );
+        return;
+    }
+
+    hkl_greek = LoadKeyboardLayout( "00000408", 0 );
+    if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
+    {
+        skip( "Unable to load Greek keyboard layout\n" );
+        return;
+    }
+
+    hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
+                            100, 100, 200, 200, 0, 0, 0, NULL );
+    flush_sequence();
+
+    PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
+
+    ok( GetMessageW( &msg, hwnd, 0, 0 ), "no message\n" );
+    ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+    ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+    ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
+    ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
+
+    DispatchMessageW( &msg );
+
+    memset( seq, 0, sizeof(seq) );
+    seq[0].message = WM_CHAR;
+    seq[0].flags = sent|wparam;
+    seq[0].wParam = 0x3b1;
+
+    ok_sequence( seq, "unicode WM_CHAR", FALSE );
+
+    flush_sequence();
+
+    /* greek alpha -> 'a' in cp1252 */
+    PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
+
+    ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
+    ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+    ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+    ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
+    ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
+
+    DispatchMessageA( &msg );
+
+    seq[0].wParam = 0x61;
+    ok_sequence( seq, "unicode WM_CHAR", FALSE );
+
+    thread_locale = GetThreadLocale();
+    ActivateKeyboardLayout( hkl_greek, 0 );
+    ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
+        thread_locale, GetThreadLocale() );
+
+    flush_sequence();
+
+    /* greek alpha -> 0xe1 in cp1253 */
+    PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
+
+    ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
+    ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
+    ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
+    ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
+    ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
+
+    DispatchMessageA( &msg );
+
+    seq[0].wParam = 0x3b1;
+    ok_sequence( seq, "unicode WM_CHAR", FALSE );
+
+    DestroyWindow( hwnd );
+    ActivateKeyboardLayout( hkl_orig, 0 );
+    UnloadKeyboardLayout( hkl_greek );
+}
+
 #define ID_LISTBOX 0x000f
 
 static const struct message wm_lb_setcursel_0[] =
@@ -14044,6 +14211,7 @@ START_TEST(msg)
     test_EndDialog();
     test_nullCallback();
     test_dbcs_wm_char();
+    test_unicode_wm_char();
     test_menu_messages();
     test_paintingloop();
     test_defwinproc();
index 59f1cce..25d6607 100644 (file)
@@ -1,10 +1,7 @@
 /* Automatically generated file; DO NOT EDIT!! */
 
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
 #define STANDALONE
-#include "wine/test.h"
+#include <wine/test.h>
 
 extern void func_broadcast(void);
 extern void func_class(void);
index a25960d..4154668 100644 (file)
@@ -1507,6 +1507,71 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id)
     DestroyWindow(mdi_child);
 }
 
+static void test_MDI_child_stack(HWND mdi_client)
+{
+    HWND child_1, child_2, child_3, child_4;
+    HWND stack[4];
+    MDICREATESTRUCTA cs;
+
+    cs.szClass = "MDI_child_Class_1";
+    cs.szTitle = "MDI child";
+    cs.hOwner  = GetModuleHandleA(0);
+    cs.x       = CW_USEDEFAULT;
+    cs.y       = CW_USEDEFAULT;
+    cs.cx      = CW_USEDEFAULT;
+    cs.cy      = CW_USEDEFAULT;
+    cs.style   = 0;
+    cs.lParam  = (LPARAM)mdi_lParam_test_message;
+
+    child_1 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
+    ok(child_1 != 0, "expected child_1 to be non NULL\n");
+    child_2 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
+    ok(child_2 != 0, "expected child_2 to be non NULL\n");
+    child_3 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
+    ok(child_3 != 0, "expected child_3 to be non NULL\n");
+    child_4 = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&cs);
+    ok(child_4 != 0, "expected child_4 to be non NULL\n");
+
+    stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    stack[1] = GetWindow(stack[0], GW_HWNDNEXT);
+    stack[2] = GetWindow(stack[1], GW_HWNDNEXT);
+    stack[3] = GetWindow(stack[2], GW_HWNDNEXT);
+    trace("Initial MDI child stack: %p->%p->%p->%p\n", stack[0], stack[1], stack[2], stack[3]);
+    ok(stack[0] == child_4 && stack[1] == child_3 &&
+        stack[2] == child_2 && stack[3] == child_1,
+        "Unexpected initial order, should be: %p->%p->%p->%p\n",
+            child_4, child_3, child_2, child_1);
+
+    trace("Activate child next to %p\n", child_3);
+    SendMessage(mdi_client, WM_MDINEXT, (WPARAM)child_3, 0);
+
+    stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    stack[1] = GetWindow(stack[0], GW_HWNDNEXT);
+    stack[2] = GetWindow(stack[1], GW_HWNDNEXT);
+    stack[3] = GetWindow(stack[2], GW_HWNDNEXT);
+    ok(stack[0] == child_2 && stack[1] == child_4 &&
+        stack[2] == child_1 && stack[3] == child_3,
+        "Broken MDI child stack:\nexpected: %p->%p->%p->%p, but got: %p->%p->%p->%p\n",
+            child_2, child_4, child_1, child_3, stack[0], stack[1], stack[2], stack[3]);
+
+    trace("Activate child previous to %p\n", child_1);
+    SendMessage(mdi_client, WM_MDINEXT, (WPARAM)child_1, 1);
+
+    stack[0] = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
+    stack[1] = GetWindow(stack[0], GW_HWNDNEXT);
+    stack[2] = GetWindow(stack[1], GW_HWNDNEXT);
+    stack[3] = GetWindow(stack[2], GW_HWNDNEXT);
+    ok(stack[0] == child_4 && stack[1] == child_2 &&
+        stack[2] == child_1 && stack[3] == child_3,
+        "Broken MDI child stack:\nexpected: %p->%p->%p->%p, but got: %p->%p->%p->%p\n",
+            child_4, child_2, child_1, child_3, stack[0], stack[1], stack[2], stack[3]);
+
+    DestroyWindow(child_1);
+    DestroyWindow(child_2);
+    DestroyWindow(child_3);
+    DestroyWindow(child_4);
+}
+
 /**********************************************************************
  * MDI_ChildGetMinMaxInfo (copied from windows/mdi.c)
  *
@@ -1788,6 +1853,17 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA
             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, GetModuleHandle(0),
+                                         &client_cs);
+            assert(mdi_client);
+            test_MDI_child_stack(mdi_client);
+            DestroyWindow(mdi_client);
             break;
         }
 
@@ -2637,7 +2713,7 @@ static void test_SetActiveWindow(HWND hwnd)
     SetActiveWindow(0);
     check_wnd_state(0, 0, 0, 0);
 
-    trace("testing SetActiveWindow %p\n", hwnd);
+    /*trace("testing SetActiveWindow %p\n", hwnd);*/
 
     ShowWindow(hwnd, SW_SHOW);
     check_wnd_state(hwnd, hwnd, hwnd, 0);
@@ -2657,11 +2733,11 @@ static void test_SetActiveWindow(HWND hwnd)
 
     SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW);
     check_wnd_state(hwnd, hwnd, hwnd, 0);
-    trace("testing ShowWindow SW_HIDE window %p\n", hwnd);
+
     ShowWindow(hwnd, SW_HIDE);
     check_wnd_state(0, 0, 0, 0);
 
-    trace("testing SetActiveWindow on an invisible window %p\n", hwnd);
+    /*trace("testing SetActiveWindow on an invisible window %p\n", hwnd);*/
     SetActiveWindow(hwnd);
     check_wnd_state(hwnd, hwnd, hwnd, 0);
     
@@ -7326,6 +7402,73 @@ static void test_map_points(void)
     DestroyWindow(wnd0);
 }
 
+static void test_update_region(void)
+{
+    HWND hwnd, parent, child;
+    HRGN  rgn1, rgn2;
+    const RECT rc = {15, 15, 40, 40};
+    const POINT wnd_orig = {30, 20};
+    const POINT child_orig = {10, 5};
+
+    parent = CreateWindowExA(0, "MainWindowClass", NULL,
+                WS_VISIBLE | WS_CLIPCHILDREN,
+                0, 0, 300, 150, NULL, NULL, GetModuleHandleA(0), 0);
+    hwnd = CreateWindowExA(0, "MainWindowClass", NULL,
+                WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD,
+                0, 0, 200, 100, parent, NULL, GetModuleHandleA(0), 0);
+    child = CreateWindowExA(0, "MainWindowClass", NULL,
+                WS_VISIBLE | WS_CHILD,
+                child_orig.x, child_orig.y,  100, 50,
+                hwnd, NULL, GetModuleHandleA(0), 0);
+    assert(parent && hwnd && child);
+
+    ValidateRgn(parent, NULL);
+    ValidateRgn(hwnd, NULL);
+    InvalidateRect(hwnd, &rc, FALSE);
+    ValidateRgn(child, NULL);
+
+    rgn1 = CreateRectRgn(0, 0, 0, 0);
+    ok(GetUpdateRgn(parent, rgn1, FALSE) == NULLREGION,
+            "has invalid area after ValidateRgn(NULL)\n");
+    GetUpdateRgn(hwnd, rgn1, FALSE);
+    rgn2 = CreateRectRgnIndirect(&rc);
+    ok(EqualRgn(rgn1, rgn2), "assigned and retrieved update regions are different\n");
+    ok(GetUpdateRgn(child, rgn2, FALSE) == NULLREGION,
+            "has invalid area after ValidateRgn(NULL)\n");
+
+    SetWindowPos(hwnd, 0, wnd_orig.x, wnd_orig.y,  0, 0,
+            SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+
+    /* parent now has non-simple update region, it consist of
+     * two rects, that was exposed after hwnd moving ... */
+    SetRectRgn(rgn1, 0, 0, 200, wnd_orig.y);
+    SetRectRgn(rgn2, 0, 0, wnd_orig.x, 100);
+    CombineRgn(rgn1, rgn1, rgn2, RGN_OR);
+    /* ... and mapped hwnd's invalid area, that hwnd has before moving */
+    SetRectRgn(rgn2, rc.left + wnd_orig.x, rc.top + wnd_orig.y,
+            rc.right + wnd_orig.x, rc.bottom + wnd_orig.y);
+    CombineRgn(rgn1, rgn1, rgn2, RGN_OR);
+    GetUpdateRgn(parent, rgn2, FALSE);
+todo_wine
+    ok(EqualRgn(rgn1, rgn2), "wrong update region\n");
+
+    /* hwnd has the same invalid region as before moving */
+    SetRectRgn(rgn1, rc.left, rc.top, rc.right, rc.bottom);
+    GetUpdateRgn(hwnd, rgn2, FALSE);
+    ok(EqualRgn(rgn1, rgn2), "wrong update region\n");
+
+    /* hwnd's invalid area maps to child during moving */
+    SetRectRgn(rgn1, rc.left - child_orig.x , rc.top - child_orig.y,
+            rc.right - child_orig.x, rc.bottom - child_orig.y);
+    GetUpdateRgn(child, rgn2, FALSE);
+todo_wine
+    ok(EqualRgn(rgn1, rgn2), "wrong update region\n");
+
+    DeleteObject(rgn1);
+    DeleteObject(rgn2);
+    DestroyWindow(parent);
+}
+
 START_TEST(win)
 {
     HMODULE user32 = GetModuleHandleA( "user32.dll" );
@@ -7438,6 +7581,7 @@ START_TEST(win)
     test_handles( hwndMain );
     test_winregion();
     test_map_points();
+    test_update_region();
 
     /* add the tests above this line */
     if (hhook) UnhookWindowsHookEx(hhook);