- update user32 winetest
authorKamil Hornicek <kamil.hornicek@reactos.org>
Fri, 28 Nov 2008 12:02:57 +0000 (12:02 +0000)
committerKamil Hornicek <kamil.hornicek@reactos.org>
Fri, 28 Nov 2008 12:02:57 +0000 (12:02 +0000)
svn path=/trunk/; revision=37702

20 files changed:
rostests/winetests/user32/broadcast.c
rostests/winetests/user32/class.c
rostests/winetests/user32/combo.c
rostests/winetests/user32/cursoricon.c
rostests/winetests/user32/dde.c
rostests/winetests/user32/dialog.c
rostests/winetests/user32/edit.c
rostests/winetests/user32/input.c
rostests/winetests/user32/listbox.c
rostests/winetests/user32/menu.c
rostests/winetests/user32/monitor.c
rostests/winetests/user32/msg.c
rostests/winetests/user32/resource.c
rostests/winetests/user32/resource.rc
rostests/winetests/user32/scroll.c
rostests/winetests/user32/static.c
rostests/winetests/user32/sysparams.c
rostests/winetests/user32/text.c
rostests/winetests/user32/win.c
rostests/winetests/user32/winstation.c

index 786df7d..ae9cd29 100644 (file)
@@ -108,14 +108,14 @@ static void test_parameters(PBROADCAST broadcast, const char *functionname)
         skip("%s is not implemented\n", functionname);
         return;
     }
-    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
-    ok(!ret, "Returned: %d\n", ret);
+    ok(!ret || broken(ret), "Returned: %d\n", ret);
+    if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
 
     SetLastError(0xcafebabe);
     recips = BSM_APPLICATIONS;
     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
-    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
-    ok(!ret, "Returned: %d\n", ret);
+    ok(!ret || broken(ret), "Returned: %d\n", ret);
+    if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
 
 #if 0 /* TODO: Check the hang flags */
     SetLastError(0xcafebabe);
@@ -150,23 +150,29 @@ static void test_parameters(PBROADCAST broadcast, const char *functionname)
     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
     PulseEvent(hevent);
 
+    SetLastError( 0xdeadbeef );
     recips = BSM_APPLICATIONS;
     ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 );
-    ok(ret==1, "Returned: %d\n", ret);
-    ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
-    PulseEvent(hevent);
-
-    recips = BSM_APPLICATIONS;
-    ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
-    ok(ret==1, "Returned: %d\n", ret);
-    ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
-    PulseEvent(hevent);
-
-    recips = BSM_APPLICATIONS;
-    ret = broadcast( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
-    ok(!ret, "Returned: %d\n", ret);
-    ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
-    PulseEvent(hevent);
+    if (ret)
+    {
+        ok(ret==1, "Returned: %d\n", ret);
+        ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
+        PulseEvent(hevent);
+
+        recips = BSM_APPLICATIONS;
+        ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
+        ok(ret==1, "Returned: %d\n", ret);
+        ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
+        PulseEvent(hevent);
+
+        recips = BSM_APPLICATIONS;
+        ret = broadcast( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
+        ok(!ret, "Returned: %d\n", ret);
+        ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
+        PulseEvent(hevent);
+    }
+    else  /* BSF_SENDNOTIFYMESSAGE not supported on NT4 */
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "failed with err %u\n", GetLastError() );
 
     recips = BSM_APPLICATIONS;
     ret = broadcast( 0, &recips, WM_NULL, 100, 0 );
@@ -264,6 +270,9 @@ static void test_noprivileges(void)
     DWORD recips;
     BOOL ret;
 
+    static const DWORD BSM_ALL_RECIPS = BSM_VXDS | BSM_NETDRIVER |
+                                        BSM_INSTALLABLEDRIVERS | BSM_APPLICATIONS;
+
     pOpenProcessToken = (void *)GetProcAddress(advapi32, "OpenProcessToken");
     pAdjustTokenPrivileges = (void *)GetProcAddress(advapi32, "AdjustTokenPrivileges");
     if (!pOpenProcessToken || !pAdjustTokenPrivileges || !pOpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
@@ -282,41 +291,44 @@ static void test_noprivileges(void)
     recips = BSM_ALLDESKTOPS;
     ResetEvent(hevent);
     ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
-    todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError());
-    ok(ret==1, "Returned: %d\n", ret);
+    ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
-    ok(recips == BSM_ALLDESKTOPS, "Received by: %08x\n", recips);
+    ok(recips == BSM_ALLDESKTOPS ||
+       recips == BSM_ALL_RECIPS, /* win2k3 */
+       "Received by: %08x\n", recips);
     PulseEvent(hevent);
 
-    /* Wine sets last error to 0, so just use that one as token here so it doesn't fail */
-    SetLastError(0);
+    SetLastError(0xcafebabe);
     recips = BSM_ALLCOMPONENTS;
     ResetEvent(hevent);
     ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
-    ok(!GetLastError(), "Last error: %08x\n", GetLastError());
-    ok(ret==1, "Returned: %d\n", ret);
+    ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
-    ok(recips == BSM_ALLCOMPONENTS, "Received by: %08x\n", recips);
+    ok(recips == BSM_ALLCOMPONENTS ||
+       recips == BSM_ALL_RECIPS, /* win2k3 */
+       "Received by: %08x\n", recips);
     PulseEvent(hevent);
 
     SetLastError(0xcafebabe);
     recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS;
     ResetEvent(hevent);
     ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
-    todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError());
-    ok(ret==1, "Returned: %d\n", ret);
+    ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
-    ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS), "Received by: %08x\n", recips);
+    ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) ||
+       recips == BSM_APPLICATIONS, /* win2k3 */
+       "Received by: %08x\n", recips);
     PulseEvent(hevent);
 
     SetLastError(0xcafebabe);
     recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS;
     ResetEvent(hevent);
     ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
-    todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError());
     ok(!ret, "Returned: %d\n", ret);
     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
-    ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS), "Received by: %08x\n", recips);
+    ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) ||
+       recips == BSM_APPLICATIONS, /* win2k3 */
+       "Received by: %08x\n", recips);
     PulseEvent(hevent);
 }
 
index 486e227..ce6d020 100755 (executable)
@@ -570,13 +570,14 @@ static void test_instances(void)
 
 static void test_builtinproc(void)
 {
-    /* Edit behaves differently. ScrollBar have currently only a Unicode winproc */
+    /* Edit behaves differently */
     static const CHAR NORMAL_CLASSES[][10] = {
         "Button",
         "Static",
         "ComboBox",
         "ComboLBox",
         "ListBox",
+        "ScrollBar",
         "#32770",  /* dialog */
     };
     static const int NUM_NORMAL_CLASSES = (sizeof(NORMAL_CLASSES)/sizeof(NORMAL_CLASSES[0]));
@@ -796,7 +797,7 @@ static BOOL RegisterTestDialog(HINSTANCE hInstance)
     wcx.hInstance = hInstance;
     wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
     wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
-    wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+    wcx.hbrBackground = GetStockObject(WHITE_BRUSH);
     wcx.lpszClassName = "TestDialog";
     wcx.lpszMenuName =  "TestDialog";
     wcx.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(5),
@@ -813,7 +814,7 @@ static BOOL RegisterTestDialog(HINSTANCE hInstance)
 
 /* test registering a dialog box created by using the CLASS directive in a
    resource file, then test creating the dialog using CreateDialogParam. */
-static void WINAPI CreateDialogParamTest(HINSTANCE hInstance)
+static void CreateDialogParamTest(HINSTANCE hInstance)
 {
     HWND hWndMain;
 
index 34d8c7a..5166007 100644 (file)
@@ -265,6 +265,103 @@ static void test_CBN_SELCHANGE(void)
     test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2);
 }
 
+static void test_WM_LBUTTONDOWN(void)
+{
+    HWND hCombo, hEdit, hList;
+    COMBOBOXINFO cbInfo;
+    UINT x, y, item_height;
+    LRESULT result;
+    int i, idx;
+    RECT rect;
+    CHAR buffer[3];
+    static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
+    static const CHAR stringFormat[] = "%2d";
+    BOOL ret;
+    BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
+
+    pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
+    if (!pGetComboBoxInfo){
+        win_skip("GetComboBoxInfo is not available\n");
+        return;
+    }
+
+    hCombo = CreateWindow("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|CBS_DROPDOWN,
+            0, 0, 200, 150, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
+
+    for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){
+        sprintf(buffer, stringFormat, choices[i]);
+        result = SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer);
+        ok(result == i,
+           "Failed to add item %d\n", i);
+    }
+
+    cbInfo.cbSize = sizeof(COMBOBOXINFO);
+    SetLastError(0xdeadbeef);
+    ret = pGetComboBoxInfo(hCombo, &cbInfo);
+    ok(ret, "Failed to get combobox info structure. LastError=%d\n",
+       GetLastError());
+    hEdit = cbInfo.hwndItem;
+    hList = cbInfo.hwndList;
+
+    trace("hMainWnd=%x, hCombo=%x, hList=%x, hEdit=%x\n",
+         (UINT)hMainWnd, (UINT)hCombo, (UINT)hList, (UINT)hEdit);
+    ok(GetFocus() == hMainWnd, "Focus not on Main Window, instead on %x\n",
+       (UINT)GetFocus());
+
+    /* Click on the button to drop down the list */
+    x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2;
+    y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2;
+    result = SendMessage(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
+    ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
+       GetLastError());
+    ok(SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0),
+       "The dropdown list should have appeared after clicking the button.\n");
+
+    ok(GetFocus() == hEdit,
+       "Focus not on ComboBox's Edit Control, instead on %x\n",
+       (UINT)GetFocus());
+    result = SendMessage(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
+    ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n",
+       GetLastError());
+    ok(GetFocus() == hEdit,
+       "Focus not on ComboBox's Edit Control, instead on %x\n",
+       (UINT)GetFocus());
+
+    /* Click on the 5th item in the list */
+    item_height = SendMessage(hCombo, CB_GETITEMHEIGHT, 0, 0);
+    ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n");
+    x = rect.left + (rect.right-rect.left)/2;
+    y = item_height/2 + item_height*4;
+    result = SendMessage(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y));
+    ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n",
+       GetLastError());
+    ok(GetFocus() == hEdit,
+       "Focus not on ComboBox's Edit Control, instead on %x\n",
+       (UINT)GetFocus());
+
+    result = SendMessage(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
+    ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n",
+       GetLastError());
+    ok(GetFocus() == hEdit,
+       "Focus not on ComboBox's Edit Control, instead on %x\n",
+       (UINT)GetFocus());
+    ok(SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0),
+       "The dropdown list should still be visible.\n");
+
+    result = SendMessage(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
+    ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n",
+       GetLastError());
+    ok(GetFocus() == hEdit,
+       "Focus not on ComboBox's Edit Control, instead on %x\n",
+       (UINT)GetFocus());
+    ok(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0),
+       "The dropdown list should have been rolled up.\n");
+    idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
+    ok(idx, "Current Selection: expected %d, got %d\n", 4, idx);
+
+    DestroyWindow(hCombo);
+}
+
 START_TEST(combo)
 {
     hMainWnd = CreateWindow("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0);
@@ -275,6 +372,7 @@ START_TEST(combo)
     test_setitemheight(CBS_DROPDOWN);
     test_setitemheight(CBS_DROPDOWNLIST);
     test_CBN_SELCHANGE();
+    test_WM_LBUTTONDOWN();
 
     DestroyWindow(hMainWnd);
 }
index 40f3a14..5d1cf2b 100644 (file)
@@ -76,11 +76,10 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARA
             SetLastError(0xdeadbeef);
             ret = DestroyCursor((HCURSOR) lParam);
             error = GetLastError();
-            todo_wine {
-            ok(!ret, "DestroyCursor on the active cursor succeeded.\n");
-            ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD,
+            todo_wine 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);
@@ -132,7 +131,7 @@ static void do_child(void)
     PostMessage(parent, PROC_INIT, (WPARAM) child, 0);
 
     /* Receive messages. */
-    while ((ret = GetMessage(&msg, child, 0, 0)))
+    while ((ret = GetMessage(&msg, 0, 0, 0)))
     {
         ok(ret != -1, "GetMessage failed.  Error: %u\n", GetLastError());
         TranslateMessage(&msg);
@@ -233,7 +232,7 @@ static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT
     BOOL orig_is_dib;
     BOOL copy_is_dib;
 
-    copy = (HBITMAP) CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
+    copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
     ok(copy != NULL, "CopyImage() failed\n");
     if (copy != NULL)
     {
@@ -504,13 +503,14 @@ static void test_CreateIcon(void)
     static const BYTE bmp_bits[1024];
     HICON hIcon;
     HBITMAP hbmMask, hbmColor;
+    BITMAPINFO *bmpinfo;
     ICONINFO info;
     HDC hdc;
+    void *bits;
     UINT display_bpp;
 
     hdc = GetDC(0);
     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
-    ReleaseDC(0, hdc);
 
     /* these crash under XP
     hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
@@ -581,6 +581,78 @@ static void test_CreateIcon(void)
 
     DeleteObject(hbmMask);
     DeleteObject(hbmColor);
+
+    /* test creating an icon from a DIB section */
+
+    bmpinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO,bmiColors[256]));
+    bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    bmpinfo->bmiHeader.biWidth = 32;
+    bmpinfo->bmiHeader.biHeight = 32;
+    bmpinfo->bmiHeader.biPlanes = 1;
+    bmpinfo->bmiHeader.biBitCount = 8;
+    bmpinfo->bmiHeader.biCompression = BI_RGB;
+    hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
+    ok(hbmColor != NULL, "Expected a handle to the DIB\n");
+    if (bits)
+        memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
+    bmpinfo->bmiHeader.biBitCount = 1;
+    hbmMask = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
+    ok(hbmMask != NULL, "Expected a handle to the DIB\n");
+    if (bits)
+        memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
+
+    info.fIcon = TRUE;
+    info.xHotspot = 8;
+    info.yHotspot = 8;
+    info.hbmMask = hbmColor;
+    info.hbmColor = hbmMask;
+    SetLastError(0xdeadbeaf);
+    hIcon = CreateIconIndirect(&info);
+    ok(hIcon != 0, "CreateIconIndirect failed\n");
+    test_icon_info(hIcon, 32, 32, 8);
+    DestroyIcon(hIcon);
+    DeleteObject(hbmColor);
+
+    bmpinfo->bmiHeader.biBitCount = 16;
+    hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
+    ok(hbmColor != NULL, "Expected a handle to the DIB\n");
+    if (bits)
+        memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
+
+    info.fIcon = TRUE;
+    info.xHotspot = 8;
+    info.yHotspot = 8;
+    info.hbmMask = hbmColor;
+    info.hbmColor = hbmMask;
+    SetLastError(0xdeadbeaf);
+    hIcon = CreateIconIndirect(&info);
+    ok(hIcon != 0, "CreateIconIndirect failed\n");
+    test_icon_info(hIcon, 32, 32, 8);
+    DestroyIcon(hIcon);
+    DeleteObject(hbmColor);
+
+    bmpinfo->bmiHeader.biBitCount = 32;
+    hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
+    ok(hbmColor != NULL, "Expected a handle to the DIB\n");
+    if (bits)
+        memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
+
+    info.fIcon = TRUE;
+    info.xHotspot = 8;
+    info.yHotspot = 8;
+    info.hbmMask = hbmColor;
+    info.hbmColor = hbmMask;
+    SetLastError(0xdeadbeaf);
+    hIcon = CreateIconIndirect(&info);
+    ok(hIcon != 0, "CreateIconIndirect failed\n");
+    test_icon_info(hIcon, 32, 32, 8);
+    DestroyIcon(hIcon);
+
+    DeleteObject(hbmMask);
+    DeleteObject(hbmColor);
+    HeapFree( GetProcessHeap(), 0, bmpinfo );
+
+    ReleaseDC(0, hdc);
 }
 
 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
@@ -664,7 +736,10 @@ static void test_LoadImageFile(const unsigned char * image_data,
     handle = LoadImageA(NULL, filename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
     ok(handle == NULL, "LoadImage(%s) as IMAGE_CURSOR succeeded incorrectly.\n", ext);
     error = GetLastError();
-    ok(error == 0, "Last error: %u\n", error);
+    ok(error == 0 ||
+        broken(error == 0xdeadbeef) || /* Win9x */
+        broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
+        "Last error: %u\n", error);
     if (handle != NULL) DestroyCursor(handle);
 
     /* Load as icon. For all tested formats, this should fail */
@@ -672,7 +747,10 @@ static void test_LoadImageFile(const unsigned char * image_data,
     handle = LoadImageA(NULL, filename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
     ok(handle == NULL, "LoadImage(%s) as IMAGE_ICON succeeded incorrectly.\n", ext);
     error = GetLastError();
-    ok(error == 0, "Last error: %u\n", error);
+    ok(error == 0 ||
+        broken(error == 0xdeadbeef) || /* Win9x */
+        broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
+        "Last error: %u\n", error);
     if (handle != NULL) DestroyIcon(handle);
 
     /* Load as bitmap. Should succeed if bmp, fail for everything else */
@@ -682,7 +760,9 @@ static void test_LoadImageFile(const unsigned char * image_data,
        ok(handle != NULL, "LoadImage(%s) as IMAGE_BITMAP failed.\n", ext);
     else ok(handle == NULL, "LoadImage(%s) as IMAGE_BITMAP succeeded incorrectly.\n", ext);
     error = GetLastError();
-    ok(error == 0, "Last error: %u\n", error);
+    ok(error == 0 ||
+        error == 0xdeadbeef, /* Win9x, WinMe */
+        "Last error: %u\n", error);
     if (handle != NULL) DeleteObject(handle);
 
     DeleteFileA(filename);
@@ -741,15 +821,16 @@ static void test_LoadImage(void)
     /* Test loading an icon as a cursor. */
     SetLastError(0xdeadbeef);
     handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
-    todo_wine
     ok(handle != NULL, "LoadImage() failed.\n");
     error = GetLastError();
-    ok(error == 0, "Last error: %u\n", error);
+    ok(error == 0 ||
+        broken(error == 0xdeadbeef) || /* Win9x */
+        broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
+        "Last error: %u\n", error);
 
     /* Test the icon information. */
     SetLastError(0xdeadbeef);
     ret = GetIconInfo(handle, &icon_info);
-    todo_wine
     ok(ret, "GetIconInfo() failed.\n");
     error = GetLastError();
     ok(error == 0xdeadbeef, "Last error: %u\n", error);
@@ -766,7 +847,6 @@ static void test_LoadImage(void)
     /* Clean up. */
     SetLastError(0xdeadbeef);
     ret = DestroyCursor(handle);
-    todo_wine
     ok(ret, "DestroyCursor() failed.\n");
     error = GetLastError();
     ok(error == 0xdeadbeef, "Last error: %u\n", error);
@@ -781,6 +861,99 @@ static void test_LoadImage(void)
     test_LoadImageFile(pngimage, sizeof(pngimage), "png", 0);
 }
 
+static void test_CreateIconFromResource(void)
+{
+    HANDLE handle;
+    BOOL ret;
+    DWORD error;
+    BITMAPINFOHEADER *icon_header;
+    INT16 *hotspot;
+    ICONINFO icon_info;
+
+#define ICON_RES_WIDTH 32
+#define ICON_RES_HEIGHT 32
+#define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
+#define ICON_RES_BPP 32
+#define ICON_RES_SIZE \
+    (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
+#define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
+
+    /* Set icon data. */
+    hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE);
+
+    /* Cursor resources have an extra hotspot, icon resources not. */
+    hotspot[0] = 3;
+    hotspot[1] = 3;
+
+    icon_header = (BITMAPINFOHEADER *) (hotspot + 2);
+    icon_header->biSize = sizeof(BITMAPINFOHEADER);
+    icon_header->biWidth = ICON_WIDTH;
+    icon_header->biHeight = ICON_HEIGHT*2;
+    icon_header->biPlanes = 1;
+    icon_header->biBitCount = ICON_BPP;
+    icon_header->biSizeImage = 0; /* Uncompressed bitmap. */
+
+    /* Test creating a cursor. */
+    SetLastError(0xdeadbeef);
+    handle = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000);
+    ok(handle != NULL, "Create cursor failed.\n");
+
+    /* Test the icon information. */
+    SetLastError(0xdeadbeef);
+    ret = GetIconInfo(handle, &icon_info);
+    ok(ret, "GetIconInfo() failed.\n");
+    error = GetLastError();
+    ok(error == 0xdeadbeef, "Last error: %u\n", error);
+
+    if (ret)
+    {
+        ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n");
+        ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot);
+        ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot);
+        ok(icon_info.hbmColor != NULL, "No hbmColor!\n");
+        ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
+    }
+
+    /* Clean up. */
+    SetLastError(0xdeadbeef);
+    ret = DestroyCursor(handle);
+    ok(ret, "DestroyCursor() failed.\n");
+    error = GetLastError();
+    ok(error == 0xdeadbeef, "Last error: %u\n", error);
+
+    /* Test creating an icon. */
+    SetLastError(0xdeadbeef);
+    handle = CreateIconFromResource((PBYTE) icon_header, ICON_RES_SIZE, TRUE,
+                                   0x00030000);
+    ok(handle != NULL, "Create icon failed.\n");
+
+    /* Test the icon information. */
+    SetLastError(0xdeadbeef);
+    ret = GetIconInfo(handle, &icon_info);
+    ok(ret, "GetIconInfo() failed.\n");
+    error = GetLastError();
+    ok(error == 0xdeadbeef, "Last error: %u\n", error);
+
+    if (ret)
+    {
+        ok(icon_info.fIcon == TRUE, "fIcon != TRUE.\n");
+       /* Icons always have hotspot in the middle */
+        ok(icon_info.xHotspot == ICON_WIDTH/2, "xHotspot is %u.\n", icon_info.xHotspot);
+        ok(icon_info.yHotspot == ICON_HEIGHT/2, "yHotspot is %u.\n", icon_info.yHotspot);
+        ok(icon_info.hbmColor != NULL, "No hbmColor!\n");
+        ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
+    }
+
+    /* Clean up. */
+    SetLastError(0xdeadbeef);
+    ret = DestroyCursor(handle);
+    ok(ret, "DestroyCursor() failed.\n");
+    error = GetLastError();
+    ok(error == 0xdeadbeef, "Last error: %u\n", error);
+
+    HeapFree(GetProcessHeap(), 0, hotspot);
+}
+
 static void test_DestroyCursor(void)
 {
     static const BYTE bmp_bits[4096];
@@ -810,24 +983,26 @@ static void test_DestroyCursor(void)
 
     SetLastError(0xdeadbeef);
     ret = DestroyCursor(cursor);
-    ok(!ret, "DestroyCursor on the active cursor succeeded\n");
+    ok(!ret || broken(ret)  /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n");
     error = GetLastError();
     ok(error == 0xdeadbeef, "Last error: %u\n", error);
-
-    cursor2 = GetCursor();
-    ok(cursor2 == cursor, "Active was set to %p when trying to destroy it\n", cursor2);
-
-    SetCursor(NULL);
-
-    /* Trying to destroy the cursor properly fails now with
-     * ERROR_INVALID_CURSOR_HANDLE.  This happens because we called
-     * DestroyCursor() 2+ times after calling SetCursor().  The calls to
-     * GetCursor() and SetCursor(NULL) in between make no difference. */
-    ret = DestroyCursor(cursor);
-    todo_wine {
-        ok(!ret, "DestroyCursor succeeded.\n");
-        error = GetLastError();
-        ok(error == ERROR_INVALID_CURSOR_HANDLE, "Last error: 0x%08x\n", error);
+    if (!ret)
+    {
+        cursor2 = GetCursor();
+        ok(cursor2 == cursor, "Active was set to %p when trying to destroy it\n", cursor2);
+        SetCursor(NULL);
+
+        /* Trying to destroy the cursor properly fails now with
+         * ERROR_INVALID_CURSOR_HANDLE.  This happens because we called
+         * DestroyCursor() 2+ times after calling SetCursor().  The calls to
+         * GetCursor() and SetCursor(NULL) in between make no difference. */
+        ret = DestroyCursor(cursor);
+        todo_wine {
+            ok(!ret, "DestroyCursor succeeded.\n");
+            error = GetLastError();
+            ok(error == ERROR_INVALID_CURSOR_HANDLE || error == 0xdeadbeef, /* vista */
+               "Last error: 0x%08x\n", error);
+        }
     }
 
     DeleteObject(cursorInfo.hbmMask);
@@ -838,7 +1013,7 @@ static void test_DestroyCursor(void)
 
     SetLastError(0xdeadbeef);
     ret = DestroyCursor(cursor);
-    ok(ret, "DestroyCursor on the active cursor failed.\n");
+    ok(ret || broken(!ret) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n");
     error = GetLastError();
     ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
 
@@ -885,6 +1060,7 @@ START_TEST(cursoricon)
     test_initial_cursor();
     test_CreateIcon();
     test_LoadImage();
+    test_CreateIconFromResource();
     test_DestroyCursor();
     do_parent();
     test_child_process();
index eb875e3..a3b73a5 100755 (executable)
@@ -73,6 +73,12 @@ static void create_dde_window(HWND *hwnd, LPCSTR name, WNDPROC wndproc)
     assert(*hwnd);
 }
 
+static void destroy_dde_window(HWND *hwnd, LPCSTR name)
+{
+    DestroyWindow(*hwnd);
+    UnregisterClass(name, GetModuleHandleA(0));
+}
+
 static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 {
     UINT_PTR lo, hi;
@@ -178,8 +184,10 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA
         ok(poke->cfFormat == CF_TEXT, "Expected CF_TEXT, got %d\n", poke->cfFormat);
 
         if (msg_index == 5)
-            ok(lstrcmpA((LPSTR)poke->Value, "poke data\r\n"),
-               "Expected 'poke data\\r\\n', got %s\n", poke->Value);
+        {
+            size = GlobalSize((HGLOBAL)lo);
+            ok(size == 4, "got %d\n", size);
+        }
         else
             ok(!lstrcmpA((LPSTR)poke->Value, "poke data\r\n"),
                "Expected 'poke data\\r\\n', got %s\n", poke->Value);
@@ -227,20 +235,21 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA
     return DefWindowProcA(hwnd, msg, wparam, lparam);
 }
 
-static void test_msg_server(HANDLE hproc)
+static void test_msg_server(HANDLE hproc, HANDLE hthread)
 {
     MSG msg;
     HWND hwnd;
     DWORD res;
 
     create_dde_window(&hwnd, "dde_server", dde_server_wndproc);
+    ResumeThread( hthread );
 
     while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0)
     {
         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
     }
 
-    DestroyWindow(hwnd);
+    destroy_dde_window(&hwnd, "dde_server");
     GetExitCodeProcess( hproc, &res );
     ok( !res, "client failed with %u error(s)\n", res );
 }
@@ -288,11 +297,8 @@ static void test_ddeml_client(void)
     DdeGetLastError(client_pid);
     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
     ret = DdeGetLastError(client_pid);
-    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
-    todo_wine
-    {
-        ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", res);
-    }
+    ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
+    ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %08x\n", res);
     if (hdata == NULL)
         ok(FALSE, "hdata is NULL\n");
     else
@@ -310,11 +316,9 @@ static void test_ddeml_client(void)
     DdeGetLastError(client_pid);
     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
     ret = DdeGetLastError(client_pid);
-    todo_wine
-    {
-        ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res);
-        ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret);
-    }
+    ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res);
+todo_wine
+    ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret);
     if (hdata == NULL)
         ok(FALSE, "hdata is NULL\n");
     else
@@ -333,10 +337,7 @@ static void test_ddeml_client(void)
     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
     ret = DdeGetLastError(client_pid);
     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
-    todo_wine
-    {
-        ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res);
-    }
+    ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res);
     if (hdata == NULL)
         ok(FALSE, "hdata is NULL\n");
     else
@@ -438,10 +439,7 @@ static void test_ddeml_client(void)
     ret = DdeGetLastError(client_pid);
     ok(op == NULL, "Expected NULL, got %p\n", op);
     ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res);
-    todo_wine
-    {
-        ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
-    }
+    ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
 
     DdeFreeStringHandle(client_pid, topic);
     DdeFreeDataHandle(hdata);
@@ -454,10 +452,7 @@ static void test_ddeml_client(void)
     hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
     ret = DdeGetLastError(client_pid);
     ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
-    todo_wine
-    {
-        ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res);
-    }
+    ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res);
     if (hdata == NULL)
         ok(FALSE, "hdata is NULL\n");
     else
@@ -662,7 +657,6 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon
 
         if (msg_index == 5)
         {
-            todo_wine
             {
                 ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str);
                 ok(size == 1, "Expected 1, got %d\n", size);
@@ -698,16 +692,12 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon
 
         ptr = (LPSTR)DdeAccessData(hdata, &size);
         ok(!lstrcmpA(ptr, "poke data\r\n"), "Expected 'poke data\\r\\n', got %s\n", ptr);
-        todo_wine
-        {
-            ok(size == 14, "Expected 14, got %d\n", size);
-        }
+        ok(size == 12, "Expected 12, got %d\n", size);
         DdeUnaccessData(hdata);
 
         size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
         if (msg_index == 7)
         {
-            todo_wine
             {
                 ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str);
                 ok(size == 1, "Expected 1, got %d\n", size);
@@ -980,7 +970,7 @@ static HGLOBAL create_poke()
     DDEPOKE *poke;
     DWORD size;
 
-    size = sizeof(DDEPOKE) + lstrlenA("poke data\r\n") + 1;
+    size = FIELD_OFFSET(DDEPOKE, Value[sizeof("poke data\r\n")]);
     hglobal = GlobalAlloc(GMEM_DDESHARE, size);
     ok(hglobal != 0, "Expected non-NULL hglobal\n");
 
@@ -1065,9 +1055,14 @@ static void test_msg_client()
 
     /* WM_DDE_POKE, no ddepoke */
     lparam = PackDDElParam(WM_DDE_POKE, 0, item);
-    PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam);
+    /* win9x returns 0 here and crashes in PostMessageA */
+    if (lparam) {
+        PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam);
+        flush_events();
+    }
+    else
+        win_skip("no lparam for WM_DDE_POKE\n");
 
-    flush_events();
 
     /* WM_DDE_POKE, no item */
     lparam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)hglobal, 0);
@@ -1123,7 +1118,7 @@ static void test_msg_client()
 
     flush_events();
 
-    DestroyWindow(client_hwnd);
+    destroy_dde_window(&client_hwnd, "dde_client");
 }
 
 static LRESULT WINAPI hook_dde_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
@@ -1186,7 +1181,6 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP
         ack.fBusy = 0;
 
         cmd = GlobalLock((HGLOBAL)hi);
-
         if (!cmd || (lstrcmpA(cmd, exec_cmdA) && lstrcmpW((LPCWSTR)cmd, exec_cmdW)))
         {
             trace("ignoring unknown WM_DDE_EXECUTE command\n");
@@ -1388,6 +1382,53 @@ todo_wine {
     DestroyWindow(hwnd_server);
 }
 
+static void test_initialisation(void)
+{
+    UINT ret;
+    DWORD res;
+    HDDEDATA hdata;
+    HSZ server, topic, item;
+    DWORD client_pid;
+    HCONV conversation;
+
+    /* Initialise without a valid server window. */
+    client_pid = 0;
+    ret = DdeInitializeA(&client_pid, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
+    ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret);
+
+
+    server = DdeCreateStringHandleA(client_pid, "TestDDEService", CP_WINANSI);
+    topic = DdeCreateStringHandleA(client_pid, "TestDDETopic", CP_WINANSI);
+
+    DdeGetLastError(client_pid);
+
+    /* There is no server window so no conversation can be extracted */
+    conversation = DdeConnect(client_pid, server, topic, NULL);
+    ok(conversation == NULL, "Expected NULL conversation, %p\n", conversation);
+    ret = DdeGetLastError(client_pid);
+    ok(ret == DMLERR_NO_CONV_ESTABLISHED, "Expected DMLERR_NO_CONV_ESTABLISHED, got %d\n", ret);
+
+    DdeFreeStringHandle(client_pid, server);
+
+    item = DdeCreateStringHandleA(client_pid, "request", CP_WINANSI);
+
+    /* There is no converstation so an invalild parameter results */
+    res = 0xdeadbeef;
+    DdeGetLastError(client_pid);
+    hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res);
+    ret = DdeGetLastError(client_pid);
+todo_wine
+    ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret);
+    ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08x\n", res);
+
+    DdeFreeStringHandle(client_pid, server);
+    ret = DdeDisconnect(conversation);
+    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
+
+    ret = DdeUninitialize(client_pid);
+    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+}
+
 static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage)
 {
     static const WCHAR dde_string[] = {'D','D','E',' ','S','t','r','i','n','g',0};
@@ -1486,15 +1527,9 @@ static void test_DdeCreateDataHandle(void)
     item = DdeCreateStringHandleA(dde_inst, "item", CP_WINANSI);
     ok(item != NULL, "Expected non-NULL hsz\n");
 
-    /* invalid instance id */
-    DdeGetLastError(dde_inst);
-    hdata = DdeCreateDataHandle(0xdeadbeef, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0);
-    err = DdeGetLastError(dde_inst);
-    todo_wine
-    {
-        ok(hdata == NULL, "Expected NULL, got %p\n", hdata);
-        ok(err == DMLERR_INVALIDPARAMETER,
-           "Expected DMLERR_INVALIDPARAMETER, got %d\n", err);
+    if (0) {
+        /* do not test with an invalid instance id: that crashes on win9x */
+        hdata = DdeCreateDataHandle(0xdeadbeef, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0);
     }
 
     /* 0 instance id */
@@ -1666,7 +1701,7 @@ static void test_DdeCreateStringHandle(void)
     ret = DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0);
     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
     {
-        trace("Skipping the DDE test on a Win9x platform\n");
+        skip("DdeInitialize is unimplemented\n");
         return;
     }
 
@@ -1690,7 +1725,7 @@ static void test_FreeDDElParam(void)
     HGLOBAL val, hglobal;
     BOOL ret;
 
-    ret = FreeDDElParam(WM_DDE_INITIATE, (LPARAM)NULL);
+    ret = FreeDDElParam(WM_DDE_INITIATE, 0);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
 
     hglobal = GlobalAlloc(GMEM_DDESHARE, 100);
@@ -1790,19 +1825,24 @@ static void test_PackDDElParam(void)
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
 
     lparam = PackDDElParam(WM_DDE_ADVISE, 0xcafe, 0xbeef);
-    ptr = GlobalLock((HGLOBAL)lparam);
-    ok(ptr != NULL, "Expected non-NULL ptr\n");
-    ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
-    ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
+    /* win9x returns 0 here */
+    if (lparam) {
+        ptr = GlobalLock((HGLOBAL)lparam);
+        ok(ptr != NULL, "Expected non-NULL ptr\n");
+        ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
+        ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
 
-    ret = GlobalUnlock((HGLOBAL)lparam);
-    ok(ret == 1, "Expected 1, got %d\n", ret);
+        ret = GlobalUnlock((HGLOBAL)lparam);
+        ok(ret == 1, "Expected 1, got %d\n", ret);
 
-    lo = hi = 0;
-    ret = UnpackDDElParam(WM_DDE_ADVISE, lparam, &lo, &hi);
-    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
-    ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
-    ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+        lo = hi = 0;
+        ret = UnpackDDElParam(WM_DDE_ADVISE, lparam, &lo, &hi);
+        ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+        ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
+        ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+    }
+    else
+        win_skip("no lparam for WM_DDE_ADVISE\n");
 
     ret = FreeDDElParam(WM_DDE_ADVISE, lparam);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -1829,42 +1869,52 @@ static void test_PackDDElParam(void)
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
 
     lparam = PackDDElParam(WM_DDE_ACK, 0xcafe, 0xbeef);
-    ptr = GlobalLock((HGLOBAL)lparam);
-    ok(ptr != NULL, "Expected non-NULL ptr\n");
-    ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
-    ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
+    /* win9x returns the input (0xbeef<<16 | 0xcafe) here */
+    if (lparam != 0xbeefcafe) {
+        ptr = GlobalLock((HGLOBAL)lparam);
+        ok(ptr != NULL, "Expected non-NULL ptr\n");
+        ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
+        ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
 
-    ret = GlobalUnlock((HGLOBAL)lparam);
-    ok(ret == 1, "Expected 1, got %d\n", ret);
+        ret = GlobalUnlock((HGLOBAL)lparam);
+        ok(ret == 1, "Expected 1, got %d\n", ret);
 
-    lo = hi = 0;
-    ret = UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
-    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
-    ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
-    ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+        lo = hi = 0;
+        ret = UnpackDDElParam(WM_DDE_ACK, lparam, &lo, &hi);
+        ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+        ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
+        ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
 
-    ret = FreeDDElParam(WM_DDE_ACK, lparam);
-    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+        ret = FreeDDElParam(WM_DDE_ACK, lparam);
+        ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
 
-    hglobal = GlobalFree((HGLOBAL)lparam);
-    ok(hglobal == (HGLOBAL)lparam, "Expected lparam, got %d\n", ret);
-    ok(GetLastError() == ERROR_INVALID_HANDLE,
-       "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+        hglobal = GlobalFree((HGLOBAL)lparam);
+        ok(hglobal == (HGLOBAL)lparam, "Expected lparam, got %d\n", ret);
+        ok(GetLastError() == ERROR_INVALID_HANDLE,
+           "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+    }
+    else
+        win_skip("got lparam 0x%lx for WM_DDE_ACK\n", lparam);
 
     lparam = PackDDElParam(WM_DDE_DATA, 0xcafe, 0xbeef);
-    ptr = GlobalLock((HGLOBAL)lparam);
-    ok(ptr != NULL, "Expected non-NULL ptr\n");
-    ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
-    ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
+    /* win9x returns 0 here */
+    if (lparam) {
+        ptr = GlobalLock((HGLOBAL)lparam);
+        ok(ptr != NULL, "Expected non-NULL ptr\n");
+        ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
+        ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
 
-    ret = GlobalUnlock((HGLOBAL)lparam);
-    ok(ret == 1, "Expected 1, got %d\n", ret);
+        ret = GlobalUnlock((HGLOBAL)lparam);
+        ok(ret == 1, "Expected 1, got %d\n", ret);
 
-    lo = hi = 0;
-    ret = UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi);
-    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
-    ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
-    ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+        lo = hi = 0;
+        ret = UnpackDDElParam(WM_DDE_DATA, lparam, &lo, &hi);
+        ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+        ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
+        ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+    }
+    else
+        win_skip("no lparam for WM_DDE_DATA\n");
 
     ret = FreeDDElParam(WM_DDE_DATA, lparam);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -1891,19 +1941,24 @@ static void test_PackDDElParam(void)
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
 
     lparam = PackDDElParam(WM_DDE_POKE, 0xcafe, 0xbeef);
-    ptr = GlobalLock((HGLOBAL)lparam);
-    ok(ptr != NULL, "Expected non-NULL ptr\n");
-    ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
-    ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
+    /* win9x returns 0 here */
+    if (lparam) {
+        ptr = GlobalLock((HGLOBAL)lparam);
+        ok(ptr != NULL, "Expected non-NULL ptr\n");
+        ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]);
+        ok(ptr[1] == 0xbeef, "Expected 0xbeef, got %08lx\n", ptr[1]);
 
-    ret = GlobalUnlock((HGLOBAL)lparam);
-    ok(ret == 1, "Expected 1, got %d\n", ret);
+        ret = GlobalUnlock((HGLOBAL)lparam);
+        ok(ret == 1, "Expected 1, got %d\n", ret);
 
-    lo = hi = 0;
-    ret = UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi);
-    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
-    ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
-    ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+        lo = hi = 0;
+        ret = UnpackDDElParam(WM_DDE_POKE, lparam, &lo, &hi);
+        ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+        ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo);
+        ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi);
+    }
+    else
+        win_skip("no lparam for WM_DDE_POKE\n");
 
     ret = FreeDDElParam(WM_DDE_POKE, lparam);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
@@ -1939,7 +1994,7 @@ static void test_UnpackDDElParam(void)
     /* NULL lParam */
     lo = 0xdead;
     hi = 0xbeef;
-    ret = UnpackDDElParam(WM_DDE_INITIATE, (LPARAM)NULL, &lo, &hi);
+    ret = UnpackDDElParam(WM_DDE_INITIATE, 0, &lo, &hi);
     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
     ok(lo == 0, "Expected 0, got %08lx\n", lo);
     ok(hi == 0, "Expected 0, got %08lx\n", hi);
@@ -1976,17 +2031,25 @@ static void test_UnpackDDElParam(void)
 
     lo = 0xdead;
     hi = 0xbeef;
-    ret = UnpackDDElParam(WM_DDE_ADVISE, (LPARAM)NULL, &lo, &hi);
+    ret = UnpackDDElParam(WM_DDE_ADVISE, 0, &lo, &hi);
     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
-    ok(lo == 0, "Expected 0, got %08lx\n", lo);
-    ok(hi == 0, "Expected 0, got %08lx\n", hi);
+    ok(lo == 0 ||
+       broken(lo == 0xdead), /* win2k */
+       "Expected 0, got %08lx\n", lo);
+    ok(hi == 0 ||
+       broken(hi == 0xbeef), /* win2k */
+       "Expected 0, got %08lx\n", hi);
 
     lo = 0xdead;
     hi = 0xbeef;
     ret = UnpackDDElParam(WM_DDE_ADVISE, 0xcafebabe, &lo, &hi);
     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
-    ok(lo == 0, "Expected 0, got %08lx\n", lo);
-    ok(hi == 0, "Expected 0, got %08lx\n", hi);
+    ok(lo == 0 ||
+       broken(lo == 0xdead), /* win2k */
+       "Expected 0, got %08lx\n", lo);
+    ok(hi == 0 ||
+       broken(hi == 0xbeef), /* win2k */
+       "Expected 0, got %08lx\n", hi);
 
     hglobal = GlobalAlloc(GMEM_DDESHARE, 2);
     ptr = GlobalLock(hglobal);
@@ -2012,8 +2075,12 @@ static void test_UnpackDDElParam(void)
     hi = 0xbeef;
     ret = UnpackDDElParam(WM_DDE_ACK, 0xcafebabe, &lo, &hi);
     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
-    ok(lo == 0, "Expected 0, got %08lx\n", lo);
-    ok(hi == 0, "Expected 0, got %08lx\n", hi);
+    ok(lo == 0 ||
+       broken(lo == 0xdead), /* win2k */
+       "Expected 0, got %08lx\n", lo);
+    ok(hi == 0 ||
+       broken(hi == 0xbeef), /* win2k */
+       "Expected 0, got %08lx\n", hi);
 
     lo = 0xdead;
     hi = 0xbeef;
@@ -2026,8 +2093,12 @@ static void test_UnpackDDElParam(void)
     hi = 0xbeef;
     ret = UnpackDDElParam(WM_DDE_DATA, 0xcafebabe, &lo, &hi);
     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
-    ok(lo == 0, "Expected 0, got %08lx\n", lo);
-    ok(hi == 0, "Expected 0, got %08lx\n", hi);
+    ok(lo == 0 ||
+       broken(lo == 0xdead), /* win2k */
+       "Expected 0, got %08lx\n", lo);
+    ok(hi == 0 ||
+       broken(hi == 0xbeef), /* win2k */
+       "Expected 0, got %08lx\n", hi);
 
     lo = 0xdead;
     hi = 0xbeef;
@@ -2047,8 +2118,12 @@ static void test_UnpackDDElParam(void)
     hi = 0xbeef;
     ret = UnpackDDElParam(WM_DDE_POKE, 0xcafebabe, &lo, &hi);
     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
-    ok(lo == 0, "Expected 0, got %08lx\n", lo);
-    ok(hi == 0, "Expected 0, got %08lx\n", hi);
+    ok(lo == 0 ||
+       broken(lo == 0xdead), /* win2k */
+       "Expected 0, got %08lx\n", lo);
+    ok(hi == 0 ||
+       broken(hi == 0xbeef), /* win2k */
+       "Expected 0, got %08lx\n", hi);
 
     lo = 0xdead;
     hi = 0xbeef;
@@ -2065,6 +2140,270 @@ static void test_UnpackDDElParam(void)
     ok(hi == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", hi);
 }
 
+static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv,
+                                               HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
+                                               ULONG_PTR dwData1, ULONG_PTR dwData2)
+{
+    DWORD size, rsize;
+    char str[MAX_PATH];
+    static int msg_index = 0;
+    static HCONV conversation = 0;
+    static char test_cmd[] = "test dde command";
+    static WCHAR test_cmd_w[] = {'t','e','s','t',' ','d','d','e',' ','c','o','m','m','a','n','d',0};
+    static char test_service [] = "TestDDEService";
+    static char test_topic [] = "TestDDETopic";
+
+    msg_index++;
+
+    switch (uType)
+    {
+    case XTYP_REGISTER:
+    {
+        ok(msg_index == 1 || msg_index == 7 || msg_index == 13 || msg_index == 19,
+                             "Expected 1, 7, 13 or 19, got %d\n", msg_index);
+        return (HDDEDATA)TRUE;
+    }
+
+    case XTYP_CONNECT:
+    {
+        ok(msg_index == 2 || msg_index == 8 || msg_index == 14 || msg_index == 20,
+                             "Expected 2, 8, 14 or 20, got %d\n", msg_index);
+        ok(uFmt == 0, "Expected 0, got %d, msg_index=%d\n", uFmt, msg_index);
+        ok(hconv == 0, "Expected 0, got %p, msg_index=%d\n", hconv, msg_index);
+        ok(hdata == 0, "Expected 0, got %p, msg_index=%d\n", hdata, msg_index);
+        ok(dwData1 != 0, "Expected not 0, got %08lx, msg_index=%d\n", dwData1, msg_index);
+        ok(dwData2 == FALSE, "Expected FALSE, got %08lx, msg_index=%d\n", dwData2, msg_index);
+
+        size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
+        ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n",
+                             test_topic, str, msg_index);
+        ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index);
+
+        size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI);
+        ok(!lstrcmpA(str, test_service), "Expected %s, got %s, msg_index=%d\n",
+                             test_service, str, msg_index);
+        ok(size == 14, "Expected 14, got %d, msg_index=%d\n", size, msg_index);
+
+        return (HDDEDATA) TRUE;
+    }
+    case XTYP_CONNECT_CONFIRM:
+    {
+        ok(msg_index == 3 || msg_index == 9  ||  msg_index == 15 ||  msg_index == 21,
+                             "Expected 3, 9, 15 or 21 got %d\n", msg_index);
+        conversation = hconv;
+        return (HDDEDATA) TRUE;
+    }
+    case XTYP_EXECUTE:
+    {
+        BYTE *buffer = NULL;
+
+        ok(msg_index == 4 || msg_index == 5 || msg_index == 10 || msg_index == 11 ||
+           msg_index == 16 || msg_index == 17 || msg_index == 22 || msg_index == 23,
+           "Expected 4, 5, 10, 11, 16, 17, 22 or 23, got %d\n", msg_index);
+        ok(uFmt == 0, "Expected 0, got %d\n", uFmt);
+        ok(hconv == conversation, "Expected conversation handle, got %p, msg_index=%d\n",
+                             hconv, msg_index);
+        ok(dwData1 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData1, msg_index);
+        ok(dwData2 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData2, msg_index);
+        ok(hsz2 == 0, "Expected 0, got %p, msg_index=%d\n", hsz2, msg_index);
+        size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI);
+        ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n",
+                             test_topic, str, msg_index);
+        ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index);
+        ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index);
+
+        size = DdeGetData(hdata, NULL, 0, 0);
+        if (msg_index == 10 || msg_index ==11 || msg_index == 16 || msg_index ==17)
+          if (msg_index == 10 || msg_index == 16)
+          todo_wine
+            ok(size == 34, "Expected that size should be 34 not %d, msg_index=%d\n",
+                             size, msg_index);
+          else
+            ok(size == 34, "Expected that size should be 34 not %d, msg_index=%d\n",
+                             size, msg_index);
+        else
+        if (msg_index ==22)
+        todo_wine
+            ok(size == 9, "Expected that size should be 9 not %d, msg_index=%d\n",
+                             size, msg_index);
+        else
+          if (msg_index == 5)
+          todo_wine
+            ok(size == 17, "Expected that size should be 17 not %d, msg_index=%d\n",
+                             size, msg_index);
+          else
+            ok(size == 17, "Expected that size should be 17 not %d, msg_index=%d\n",
+                             size, msg_index);
+        ok((buffer = HeapAlloc(GetProcessHeap(), 0, size)) != NULL, "should not be null\n");
+        rsize = DdeGetData(hdata, buffer, size, 0);
+        if (msg_index == 10 || msg_index == 11 || msg_index == 16 || msg_index ==17)
+        {
+            ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n",
+                             size, rsize, msg_index);
+          if (msg_index == 10 || msg_index == 16)
+          todo_wine {
+            ok(!lstrcmpW((WCHAR*)buffer, test_cmd_w),
+                             "Expected \"Test dde command\", msg_index=%d\n",
+                             msg_index);
+            ok(size == 34, "Expected 34, got %d, msg_index=%d\n", size, msg_index);
+          } else
+          {
+            ok(!lstrcmpW((WCHAR*)buffer, test_cmd_w),
+                             "Expected \"Test dde command\", msg_index=%d\n",
+                             msg_index);
+            ok(size == 34, "Expected 34, got %d, msg_index=%d\n", size, msg_index);
+          }
+        }else if (msg_index == 22)
+        {
+            ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n",
+                             size, rsize, msg_index);
+        } else
+        {
+            ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n",
+                             size, rsize, msg_index);
+          if (msg_index == 5)
+          todo_wine {
+            ok(!lstrcmpA((CHAR*)buffer, test_cmd), "Expected %s, got %s, msg_index=%d\n",
+                             test_cmd, buffer, msg_index);
+            ok(size == 17, "Expected size should be 17, got %d, msg_index=%d\n", size, msg_index);
+          }
+          else
+          {
+            ok(!lstrcmpA((CHAR*)buffer, test_cmd), "Expected %s, got %s, msg_index=%d\n",
+                             test_cmd, buffer, msg_index);
+            ok(size == 17, "Expected size should be 17, got %d, msg_index=%d\n", size, msg_index);
+          }
+
+        }
+
+        return (HDDEDATA) DDE_FACK;
+    }
+    case XTYP_DISCONNECT:
+        return (HDDEDATA) TRUE;
+
+    default:
+        ok(FALSE, "Unhandled msg: %08x, msg_index=%d\n", uType, msg_index);
+    }
+
+    return NULL;
+}
+
+static HDDEDATA CALLBACK client_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv,
+                                               HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
+                                               ULONG_PTR dwData1, ULONG_PTR dwData2)
+{
+    switch (uType)
+    {
+    case XTYP_DISCONNECT:
+        return (HDDEDATA) TRUE;
+
+    default:
+        ok(FALSE, "Unhandled msg: %08x\n", uType);
+    }
+
+    return NULL;
+}
+
+static void test_end_to_end_client(BOOL type_a)
+{
+    DWORD  ret, err;
+    DWORD client_pid = 0;
+    HSZ server, topic;
+    HCONV hconv;
+    HDDEDATA hdata;
+    static char test_cmd[] = "test dde command";
+    static WCHAR test_cmd_w[] = {'t','e','s','t',' ','d','d','e',' ','c','o','m','m','a','n','d',0};
+    static char test_service[] = "TestDDEService";
+    static WCHAR test_service_w[] = {'T','e','s','t','D','D','E','S','e','r','v','i','c','e',0};
+    static char test_topic[] = "TestDDETopic";
+    static WCHAR test_topic_w[] = {'T','e','s','t','D','D','E','T','o','p','i','c',0};
+
+    trace("Start end to end client %d\n", type_a);
+
+    if (type_a)
+        ret = DdeInitializeA(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0);
+    else
+        ret = DdeInitializeW(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0);
+    ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret);
+
+    if (type_a)
+    {
+        server = DdeCreateStringHandleA(client_pid, test_service, CP_WINANSI);
+        topic = DdeCreateStringHandleA(client_pid, test_topic, CP_WINANSI);
+    }
+    else {
+        server = DdeCreateStringHandleW(client_pid, test_service_w, CP_WINUNICODE);
+        topic = DdeCreateStringHandleW(client_pid, test_topic_w, CP_WINUNICODE);
+    }
+
+    DdeGetLastError(client_pid);
+    hconv = DdeConnect(client_pid, server, topic, NULL);
+    ok(hconv != NULL, "Expected non-NULL conversation\n");
+    ret = DdeGetLastError(client_pid);
+    ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret);
+    DdeFreeStringHandle(client_pid, server);
+
+    /* Test both A and W data being passed to DdeClientTransaction */
+    hdata = DdeClientTransaction((LPBYTE)test_cmd, strlen(test_cmd) + 1,
+            hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret);
+    ok(hdata != NULL, "DdeClientTransaction failed\n");
+    ok(ret == DDE_FACK, "wrong status code %x\n", ret);
+    err = DdeGetLastError(client_pid);
+    ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
+
+    hdata = DdeClientTransaction((LPBYTE)test_cmd_w, lstrlenW(test_cmd_w) * sizeof(WCHAR) + 2,
+            hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret);
+    ok(hdata != NULL, "DdeClientTransaction failed\n");
+    ok(ret == DDE_FACK, "wrong status code %x\n", ret);
+    err = DdeGetLastError(client_pid);
+    ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err);
+
+    DdeFreeStringHandle(client_pid, topic);
+    ret = DdeDisconnect(hconv);
+    ok(ret == TRUE, "Expected TRUE, got %x\n", ret);
+
+    ret = DdeUninitialize(client_pid);
+    ok(ret == TRUE, "Expected TRUE, got %x\n", ret);
+
+}
+
+static void test_end_to_end_server(HANDLE hproc, HANDLE hthread, BOOL type_a)
+{
+    MSG msg;
+    HSZ server;
+    BOOL ret;
+    DWORD res;
+    HDDEDATA hdata;
+    static CHAR test_service[] = "TestDDEService";
+
+    trace("start end to end server %d\n", type_a);
+    server_pid = 0;
+
+    if (type_a)
+        res = DdeInitializeA(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0);
+    else
+        res = DdeInitializeW(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0);
+    ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res);
+
+    server = DdeCreateStringHandleA(server_pid, test_service, CP_WINANSI);
+    ok(server != NULL, "Expected non-NULL string handle\n");
+
+    hdata = DdeNameService(server_pid, server, 0, DNS_REGISTER);
+    ok(hdata == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", hdata);
+    ResumeThread( hthread );
+
+
+    while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0)
+    {
+        while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    }
+
+    ret = DdeUninitialize(server_pid);
+    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+    GetExitCodeProcess( hproc, &res );
+    ok( !res, "client failed with %u error(s)\n", res );
+}
+
 START_TEST(dde)
 {
     int argc;
@@ -2080,10 +2419,16 @@ START_TEST(dde)
             test_ddeml_client();
         else if (!lstrcmpA(argv[2], "msg"))
             test_msg_client();
+        else if (!lstrcmpA(argv[2], "enda"))
+            test_end_to_end_client(TRUE);
+        else if (!lstrcmpA(argv[2], "endw"))
+            test_end_to_end_client(FALSE);
 
         return;
     }
 
+    test_initialisation();
+
     ZeroMemory(&startup, sizeof(STARTUPINFO));
     sprintf(buffer, "%s dde ddeml", argv[0]);
     startup.cb = sizeof(startup);
@@ -2091,9 +2436,9 @@ START_TEST(dde)
     startup.wShowWindow = SW_SHOWNORMAL;
 
     CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
-                   0, NULL, NULL, &startup, &proc);
+                   CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
 
-    test_msg_server(proc.hProcess);
+    test_msg_server(proc.hProcess, proc.hThread);
 
     sprintf(buffer, "%s dde msg", argv[0]);
     CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
@@ -2101,6 +2446,32 @@ START_TEST(dde)
 
     test_ddeml_server(proc.hProcess);
 
+    /* Test the combinations of A and W interfaces with A and W data
+       end to end to ensure that data conversions are accurate */
+    sprintf(buffer, "%s dde enda", argv[0]);
+    CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
+                   CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
+
+    test_end_to_end_server(proc.hProcess, proc.hThread, TRUE);
+
+    sprintf(buffer, "%s dde endw", argv[0]);
+    CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
+                   CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
+
+    test_end_to_end_server(proc.hProcess, proc.hThread, FALSE);
+
+    sprintf(buffer, "%s dde enda", argv[0]);
+    CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
+                   CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
+
+    test_end_to_end_server(proc.hProcess, proc.hThread, FALSE);
+
+    sprintf(buffer, "%s dde endw", argv[0]);
+    CreateProcessA(NULL, buffer, NULL, NULL, FALSE,
+                   CREATE_SUSPENDED, NULL, NULL, &startup, &proc);
+
+    test_end_to_end_server(proc.hProcess, proc.hThread, TRUE);
+
     test_dde_aw_transaction();
 
     test_DdeCreateDataHandle();
index 8bf3c29..f92566c 100755 (executable)
@@ -874,7 +874,7 @@ static void InitialFocusTest (void)
 
         hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", (LPSTR)RT_DIALOG);
         hTemplate = LoadResource(g_hinst, hResource);
-        pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
+        pTemplate = LockResource(hTemplate);
 
         g_hwndInitialFocusT1 = 0;
         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
@@ -896,7 +896,8 @@ static void test_GetDlgItemText(void)
     ret = GetDlgItemTextA(NULL, 0, string, sizeof(string)/sizeof(string[0]));
     ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n");
 
-    ok(string[0] == '\0', "string retrieved using GetDlgItemText should have been NULL terminated\n");
+    ok(string[0] == '\0' || broken(!strcmp(string, "Overwrite Me")),
+       "string retrieved using GetDlgItemText should have been NULL terminated\n");
 }
 
 static void test_DialogBoxParamA(void)
@@ -906,12 +907,16 @@ static void test_DialogBoxParamA(void)
 
     SetLastError(0xdeadbeef);
     ret = DialogBoxParamA(GetModuleHandle(NULL), "IDD_DIALOG" , hwnd_invalid, 0 , 0);
-    ok(0 == ret, "DialogBoxParamA returned %d, expected 0\n", ret);
-    ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError(),"got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
+    ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %d, expected 0\n", ret);
+    ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
+       broken(GetLastError() == 0xdeadbeef),
+       "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
     SetLastError(0xdeadbeef);
     ret = DialogBoxParamA(GetModuleHandle(NULL), "RESOURCE_INVALID" , 0, 0, 0);
     ok(-1 == ret, "DialogBoxParamA returned %d, expected -1\n", ret);
-    ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError(),"got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError());
+    ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError() ||
+       broken(GetLastError() == 0xdeadbeef),
+       "got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError());
 }
 
 static void test_DisabledDialogTest(void)
index 0c5a678..f6dc918 100755 (executable)
@@ -1336,30 +1336,41 @@ static void test_margins_font_change(void)
     SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0));
     SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
     margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
-    ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins));
-    ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));
+    ok(LOWORD(margins) == 0 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */
+       "got %d\n", LOWORD(margins));
+    ok(HIWORD(margins) == 0 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */
+       "got %d\n", HIWORD(margins));
+
     SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
     SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
     margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
-    ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
-    ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins));  
+    ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */
+       "got %d\n", LOWORD(margins));
+    ok(HIWORD(margins) == 0 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */
+       "got %d\n", HIWORD(margins));
 
     SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1));
     SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0);
     margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
-    ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
-    ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins));  
+    ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */
+       "got %d\n", LOWORD(margins));
+    ok(HIWORD(margins) == 1 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */
+       "got %d\n", HIWORD(margins));
 
     SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO));
     margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
-    ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
-    ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); 
+    ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */
+       "got %d\n", LOWORD(margins));
+    ok(HIWORD(margins) == 1 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */
+       "got %d\n", HIWORD(margins));
+
     SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
     margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
-    ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins));
-    ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); 
+    ok(LOWORD(margins) == 1 || broken(LOWORD(margins) != 1 && LOWORD(margins) != LOWORD(font_margins)), /* win95 */
+       "got %d\n", LOWORD(margins));
+    ok(HIWORD(margins) == 1 || broken(HIWORD(margins) != 1 && HIWORD(margins) != HIWORD(font_margins)), /* win95 */
+       "got %d\n", HIWORD(margins));
+
     /* Above a certain size threshold then the margin is updated */
     SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE);
     SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0));
@@ -1380,7 +1391,8 @@ static void test_margins_font_change(void)
     ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins)); 
     SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0);
     margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
-    ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins));
+    ok(LOWORD(margins) != LOWORD(font_margins) || broken(LOWORD(margins) == LOWORD(font_margins)), /* win98 */
+       "got %d\n", LOWORD(margins));
     ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins)); 
 
     SendMessageA(hwEdit, WM_SETFONT, 0, 0);
@@ -1989,6 +2001,53 @@ static void UnregisterWindowClasses (void)
     UnregisterClassA(szEditTextPositionClass, hinst);
 }
 
+void test_fontsize(void)
+{
+    HWND hwEdit;
+    HFONT hfont;
+    LOGFONT lf;
+    LONG r;
+    char szLocalString[MAXLEN];
+
+    memset(&lf,0,sizeof(LOGFONTA));
+    strcpy(lf.lfFaceName,"Arial");
+    lf.lfHeight = -300; /* taller than the edit box */
+    lf.lfWeight = 500;
+    hfont = CreateFontIndirect(&lf);
+
+    trace("EDIT: Oversized font (Multi line)\n");
+    hwEdit= CreateWindow("EDIT", NULL, ES_MULTILINE|ES_AUTOHSCROLL,
+                           0, 0, 150, 50, NULL, NULL, hinst, NULL);
+
+    SendMessage(hwEdit,WM_SETFONT,(WPARAM)hfont,0);
+
+    if (winetest_interactive)
+        ShowWindow (hwEdit, SW_SHOW);
+
+    r = SendMessage(hwEdit, WM_CHAR, 'A', 1);
+    ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+    r = SendMessage(hwEdit, WM_CHAR, 'B', 1);
+    ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+    r = SendMessage(hwEdit, WM_CHAR, 'C', 1);
+    ok(1 == r, "Expected: %d, got: %d\n", 1, r);
+
+    GetWindowText(hwEdit, szLocalString, MAXLEN);
+    ok(lstrcmp(szLocalString, "ABC")==0,
+       "Wrong contents of edit: %s\n", szLocalString);
+
+    r = SendMessage(hwEdit, EM_POSFROMCHAR,0,0);
+    ok(r != -1,"EM_POSFROMCHAR failed index 0\n");
+    r = SendMessage(hwEdit, EM_POSFROMCHAR,1,0);
+    ok(r != -1,"EM_POSFROMCHAR failed index 1\n");
+    r = SendMessage(hwEdit, EM_POSFROMCHAR,2,0);
+    ok(r != -1,"EM_POSFROMCHAR failed index 2\n");
+    r = SendMessage(hwEdit, EM_POSFROMCHAR,3,0);
+    ok(r == -1,"EM_POSFROMCHAR succeeded index 3\n");
+
+    DestroyWindow (hwEdit);
+    DeleteObject(hfont);
+}
+
 START_TEST(edit)
 {
     hinst = GetModuleHandleA(NULL);
@@ -2012,6 +2071,7 @@ START_TEST(edit)
     test_wantreturn_edit_dialog();
     test_singleline_wantreturn_edit_dialog();
     test_child_edit_wmkeydown();
+    test_fontsize();
 
     UnregisterWindowClasses();
 }
index 0876709..4297fe2 100755 (executable)
@@ -357,17 +357,31 @@ static void test_Input_whitebox(void)
     DestroyWindow(hWndTest);
 }
 
-static void empty_message_queue(void) {
+/* try to make sure pending X events have been processed before continuing */
+static void empty_message_queue(void)
+{
     MSG msg;
-    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
-        TranslateMessage(&msg);
-        DispatchMessage(&msg);
+    int diff = 200;
+    int min_timeout = 50;
+    DWORD time = GetTickCount() + diff;
+
+    while (diff > 0)
+    {
+        if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
+        while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+        {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+        diff = time - GetTickCount();
+        min_timeout = 20;
     }
 }
 
 struct transition_s {
     WORD wVk;
     BYTE before_state;
+    BYTE optional;
 };
 
 typedef enum {
@@ -398,6 +412,7 @@ struct sendinput_test_s {
     struct message expected_messages[MAXKEYMESSAGES+1];
 } sendinput_test[] = {
     /* test ALT+F */
+    /* 0 */
     {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
         {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}},
     {'F', 0, 0, {{'F', 0x00}, {0}},
@@ -410,6 +425,7 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
 
     /* test CTRL+O */
+    /* 4 */
     {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
     {'O', 0, 0, {{'O', 0x00}, {0}},
@@ -420,6 +436,7 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
 
     /* test ALT+CTRL+X */
+    /* 8 */
     {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
         {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}},
     {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
@@ -434,6 +451,7 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
 
     /* test SHIFT+A */
+    /* 14 */
     {VK_LSHIFT, 0, 0, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
         {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}},
     {'A', 0, 0, {{'A', 0x00}, {0}},
@@ -444,16 +462,19 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}},
     /* test L-SHIFT & R-SHIFT: */
     /* RSHIFT == LSHIFT */
+    /* 18 */
     {VK_RSHIFT, 0, 0,
-        {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
+     /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */
+       {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00, TRUE}, {VK_RSHIFT, 0x00, TRUE}, {0}},
         {{WM_KEYDOWN, hook|wparam, VK_RSHIFT},
         {WM_KEYDOWN}, {0}}},
     {VK_RSHIFT, KEYEVENTF_KEYUP, 0,
-        {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
+       {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80, TRUE}, {VK_RSHIFT, 0x80, TRUE}, {0}},
         {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT},
         {WM_KEYUP}, {0}}},
 
     /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
+    /* 20 */
     {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
         {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED},
@@ -463,6 +484,7 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED},
         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
     /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
+    /* 22 */
     {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
         {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED},
@@ -471,27 +493,35 @@ struct sendinput_test_s {
         {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
         {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED},
         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
+
+    /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU):
+       win2k  - sends to hook whatever we generated here
+       winXP+ - Attempts to convert key to L/R key but not always correct
+    */
     /* SHIFT == LSHIFT */
+    /* 24 */
     {VK_SHIFT, 0, 0,
         {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
-        {{WM_KEYDOWN, hook|wparam|lparam, VK_SHIFT, 0},
+        {{WM_KEYDOWN, hook/* |wparam */|lparam, VK_SHIFT, 0},
         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
     {VK_SHIFT, KEYEVENTF_KEYUP, 0,
         {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}},
-        {{WM_KEYUP, hook|wparam|lparam, VK_SHIFT, LLKHF_UP},
+        {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP},
         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
     /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */
+    /* 26 */
     {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}},
-        {{WM_KEYDOWN, hook|wparam|lparam, VK_SHIFT, LLKHF_EXTENDED},
+        {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_EXTENDED},
         {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}},
     {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}},
-        {{WM_KEYUP, hook|wparam|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED},
+        {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED},
         {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}},
 
     /* test L-CONTROL & R-CONTROL: */
     /* RCONTROL == LCONTROL */
+    /* 28 */
     {VK_RCONTROL, 0, 0,
         {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
         {{WM_KEYDOWN, hook|wparam, VK_RCONTROL},
@@ -501,6 +531,7 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook|wparam, VK_RCONTROL},
         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
     /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
+    /* 30 */
     {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
         {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED},
@@ -510,6 +541,7 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED},
         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
     /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
+    /* 32 */
     {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
         {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED},
@@ -519,26 +551,29 @@ struct sendinput_test_s {
         {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED},
         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
     /* CONTROL == LCONTROL */
+    /* 34 */
     {VK_CONTROL, 0, 0,
         {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}},
-        {{WM_KEYDOWN, hook|wparam, VK_CONTROL},
+        {{WM_KEYDOWN, hook/*|wparam, VK_CONTROL*/},
         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}},
     {VK_CONTROL, KEYEVENTF_KEYUP, 0,
         {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}},
-        {{WM_KEYUP, hook|wparam, VK_CONTROL},
+        {{WM_KEYUP, hook/*|wparam, VK_CONTROL*/},
         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}},
     /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */
+    /* 36 */
     {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}},
-        {{WM_KEYDOWN, hook|wparam|lparam, VK_CONTROL, LLKHF_EXTENDED},
+        {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_EXTENDED},
         {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}},
     {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}},
-        {{WM_KEYUP, hook|wparam|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED},
+        {{WM_KEYUP, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED},
         {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}},
 
     /* test L-MENU & R-MENU: */
     /* RMENU == LMENU */
+    /* 38 */
     {VK_RMENU, 0, 0,
         {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
         {{WM_SYSKEYDOWN, hook|wparam, VK_RMENU},
@@ -549,6 +584,7 @@ struct sendinput_test_s {
         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
         {WM_SYSCOMMAND}, {0}}},
     /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
+    /* 40 */
     {VK_LMENU, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}},
         {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED},
@@ -559,6 +595,7 @@ struct sendinput_test_s {
         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
         {WM_SYSCOMMAND}, {0}}},
     /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */
+    /* 42 */
     {VK_RMENU, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}},
         {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED},
@@ -569,27 +606,30 @@ struct sendinput_test_s {
         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
         {WM_SYSCOMMAND}, {0}}},
     /* MENU == LMENU */
+    /* 44 */
     {VK_MENU, 0, 0,
         {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}},
-        {{WM_SYSKEYDOWN, hook|wparam, VK_MENU},
+        {{WM_SYSKEYDOWN, hook/*|wparam, VK_MENU*/},
         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}},
     {VK_MENU, KEYEVENTF_KEYUP, 1,
         {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}},
-        {{WM_KEYUP, hook|wparam, VK_MENU},
+        {{WM_KEYUP, hook/*|wparam, VK_MENU*/},
         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP},
         {WM_SYSCOMMAND}, {0}}},
     /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */
+    /* 46 */
     {VK_MENU, KEYEVENTF_EXTENDEDKEY, 0,
         {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}},
-        {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_MENU, LLKHF_EXTENDED},
+        {{WM_SYSKEYDOWN, hook/*|wparam*/|lparam, VK_MENU, LLKHF_EXTENDED},
         {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}},
     {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1,
         {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}},
-        {{WM_KEYUP, hook|wparam|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED},
+        {{WM_KEYUP, hook/*|wparam*/|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED},
         {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED},
         {WM_SYSCOMMAND}, {0}}},
 
     /* test LSHIFT & RSHIFT */
+    /* 48 */
     {VK_LSHIFT, 0, 0,
         {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}},
         {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0},
@@ -629,15 +669,15 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
         {
             failcount++;
             todo_wine {
-                ok(matched, "%02d: %02x from %02x -> %02x "
-                   "instead of %02x -> %02x\n", id, t->wVk,
-                   ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
+                ok(matched, "%2d (%x/%x): %02x from %02x -> %02x "
+                   "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
+                   t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
                    ~t->before_state&0x80);
             }
         } else {
-            ok(matched, "%02d: %02x from %02x -> %02x "
-               "instead of %02x -> %02x\n", id, t->wVk,
-               ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
+            ok(matched || t->optional, "%2d (%x/%x): %02x from %02x -> %02x "
+               "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags,
+               t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state,
                ~t->before_state&0x80);
         }
         ks2[t->wVk] = ks1[t->wVk]; /* clear the match */
@@ -648,11 +688,12 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
         {
             failcount++;
             todo_wine
-                ok(FALSE, "%02d: %02x from %02x -> %02x unexpected\n", id, i, ks1[i], ks2[i]);
+                ok(FALSE, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
+                   id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
         }
         else
-            ok(ks2[i] == ks1[i], "%02d: %02x from %02x -> %02x unexpected\n",
-               id, i, ks1[i], ks2[i]);
+            ok(ks2[i] == ks1[i], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n",
+               id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]);
 
     while (expected->message && actual_cnt < sent_messages_cnt)
     {
@@ -661,8 +702,8 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
         if (expected->message == actual->message)
         {
             ok((expected->flags & hook) == (actual->flags & hook),
-               "%x/%x: the msg 0x%04x should have been sent by a hook\n",
-               test->wVk, test->dwFlags, expected->message);
+               "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n",
+               id, test->wVk, test->dwFlags, expected->message);
 
             if (expected->flags & wparam)
             {
@@ -670,13 +711,13 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
                 {
                     failcount++;
                     todo_wine
-                        ok(FALSE, "%x/%x: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
-                           test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
+                        ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
+                           id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
                 }
                 else
                     ok(expected->wParam == actual->wParam,
-                       "%x/%x: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
-                       test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
+                       "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
+                       id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam);
             }
             if (expected->flags & lparam)
             {
@@ -684,13 +725,13 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
                 {
                     failcount++;
                     todo_wine
-                        ok(FALSE, "%x/%x: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
-                           test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
+                        ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
+                           id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
                 }
                 else
                     ok(expected->lParam == actual->lParam,
-                       "%x/%x: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
-                       test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
+                       "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
+                       id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam);
             }
         }
         else if (expected->flags & optional)
@@ -703,13 +744,13 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
             failcount++;
             todo_wine
             ok(FALSE,
-               "%x/%x: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
-               test->wVk, test->dwFlags, expected->message, actual->message);
+               "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
+               id, test->wVk, test->dwFlags, expected->message, actual->message);
         }
         else
             ok(FALSE,
-               "%x/%x: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
-               test->wVk, test->dwFlags, expected->message, actual->message);
+               "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n",
+               id, test->wVk, test->dwFlags, expected->message, actual->message);
 
         actual_cnt++;
         expected++;
@@ -725,17 +766,17 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes
         {
             failcount++;
             todo_wine
-                ok(FALSE, "%x/%x: the msg sequence is not complete: expected %04x - actual %04x\n",
-                   test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
+                ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
+                   id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
         }
         else
-            ok(FALSE, "%x/%x: the msg sequence is not complete: expected %04x - actual %04x\n",
-               test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
+            ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n",
+               id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message);
     }
 
     if( test->_todo_wine && !failcount) /* succeeded yet marked todo */
         todo_wine
-            ok(TRUE, "%x/%x: marked \"todo_wine\" but succeeds\n", test->wVk, test->dwFlags);
+            ok(TRUE, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id, test->wVk, test->dwFlags);
 
     sent_messages_cnt = 0;
 }
@@ -1000,19 +1041,19 @@ static void test_GetMouseMovePointsEx(void)
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(0, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)+1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     /* test second and third parameter
@@ -1020,7 +1061,7 @@ static void test_GetMouseMovePointsEx(void)
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_NOACCESS == GetLastError(),
+    ok(GetLastError() == ERROR_NOACCESS || GetLastError() == MYERROR,
        "expected error ERROR_NOACCESS, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
@@ -1051,7 +1092,7 @@ static void test_GetMouseMovePointsEx(void)
     count = -1;
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS);
     ok(retval == count, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
@@ -1075,7 +1116,7 @@ static void test_GetMouseMovePointsEx(void)
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     /* it was not possible to force an error with the fifth parameter on win2k */
@@ -1084,25 +1125,25 @@ static void test_GetMouseMovePointsEx(void)
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
     SetLastError(MYERROR);
     retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM+1, GMMP_USE_DISPLAY_POINTS);
     ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval);
-    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR,
        "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
 
 #undef BUFLIM
@@ -1113,6 +1154,18 @@ static void test_key_map(void)
 {
     HKL kl = GetKeyboardLayout(0);
     UINT kL, kR, s, sL;
+    int i;
+    static const UINT numpad_collisions[][2] = {
+        { VK_NUMPAD0, VK_INSERT },
+        { VK_NUMPAD1, VK_END },
+        { VK_NUMPAD2, VK_DOWN },
+        { VK_NUMPAD3, VK_NEXT },
+        { VK_NUMPAD4, VK_LEFT },
+        { VK_NUMPAD6, VK_RIGHT },
+        { VK_NUMPAD7, VK_HOME },
+        { VK_NUMPAD8, VK_UP },
+        { VK_NUMPAD9, VK_PRIOR },
+    };
 
     s  = MapVirtualKeyEx(VK_SHIFT,  MAPVK_VK_TO_VSC, kl);
     ok(s != 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n");
@@ -1128,6 +1181,60 @@ static void test_key_map(void)
     ok(kL == VK_LSHIFT, "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL);
     kR = MapVirtualKeyEx(0x36, MAPVK_VSC_TO_VK_EX, kl);
     ok(kR == VK_RSHIFT, "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR);
+
+    /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */
+    for (i = 0; i < sizeof(numpad_collisions)/sizeof(numpad_collisions[0]); i++)
+    {
+        UINT numpad_scan = MapVirtualKeyEx(numpad_collisions[i][0],  MAPVK_VK_TO_VSC, kl);
+        UINT other_scan  = MapVirtualKeyEx(numpad_collisions[i][1],  MAPVK_VK_TO_VSC, kl);
+
+        /* do they really collide for this layout? */
+        if (numpad_scan && other_scan == numpad_scan)
+        {
+            UINT vkey = MapVirtualKeyEx(numpad_scan, MAPVK_VSC_TO_VK, kl);
+            ok(vkey != numpad_collisions[i][0],
+               "Got numpad vKey %x for scan code %x when there was another choice\n",
+               vkey, numpad_scan);
+        }
+    }
+}
+
+static void test_ToUnicode(void)
+{
+    WCHAR wStr[2];
+    BYTE state[256];
+    const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f;
+    const BYTE HIGHEST_BIT = 0x80;
+    int i, ret;
+    for(i=0; i<256; i++)
+        state[i]=0;
+
+    SetLastError(0xdeadbeef);
+    ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("ToUnicode is not implemented\n");
+        return;
+    }
+
+    ok(ret == 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret);
+    if(ret == 1)
+        ok(wStr[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr[0]);
+    state[VK_CONTROL] |= HIGHEST_BIT;
+    state[VK_LCONTROL] |= HIGHEST_BIT;
+
+    ret = ToUnicode(VK_TAB, SC_TAB, state, wStr, 2, 0);
+    todo_wine ok(ret == 0, "ToUnicode for CTRL + Tab didn't return 0 (was %i)\n", ret);
+
+    ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0);
+    ok(ret == 1, "ToUnicode for CTRL + Return didn't return 1 (was %i)\n", ret);
+    if(ret == 1)
+        ok(wStr[0]=='\n', "ToUnicode for CTRL + Return was %i (expected 10)\n", wStr[0]);
+
+    state[VK_SHIFT] |= HIGHEST_BIT;
+    state[VK_LSHIFT] |= HIGHEST_BIT;
+    ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0);
+    todo_wine ok(ret == 0, "ToUnicode for CTRL + SHIFT + Return didn't return 0 (was %i)\n", ret);
 }
 
 START_TEST(input)
@@ -1143,6 +1250,7 @@ START_TEST(input)
     test_keynames();
     test_mouse_ll_hook();
     test_key_map();
+    test_ToUnicode();
 
     if(pGetMouseMovePointsEx)
         test_GetMouseMovePointsEx();
index 5e650e0..c872357 100644 (file)
@@ -44,7 +44,7 @@ static const char * const strings[4] = {
   "Fourth added which is very long because at some time we only had a 256 byte character buffer and that was overflowing in one of those applications that had a common dialog file open box and tried to add a 300 characters long custom filter string which of course the code did not like and crashed. Just make sure this string is longer than 256 characters."
 };
 
-static const char BAD_EXTENSION[] = "*.txtbad";
+static const char BAD_EXTENSION[] = "*.badtxt";
 
 static HWND
 create_listbox (DWORD add_style, HWND parent)
@@ -103,8 +103,8 @@ buttonpress (HWND handle, WORD x, WORD y)
   LPARAM lp=x+(y<<16);
 
   WAIT;
-  SendMessage (handle, WM_LBUTTONDOWN, (WPARAM) MK_LBUTTON, lp);
-  SendMessage (handle, WM_LBUTTONUP  , (WPARAM) 0         , lp);
+  SendMessage (handle, WM_LBUTTONDOWN, MK_LBUTTON, lp);
+  SendMessage (handle, WM_LBUTTONUP, 0, lp);
   REDRAW;
 }
 
@@ -254,7 +254,9 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA
                rc_client.left, rc_client.top, rc_client.right, rc_client.bottom);
         GetClipBox(dis->hDC, &rc_clip);
         trace("clip rect (%d,%d-%d,%d)\n", rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
-        ok(EqualRect(&rc_client, &rc_clip), "client rect of the listbox should be equal to the clip box\n");
+        ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip),
+           "client rect of the listbox should be equal to the clip box,"
+           "or the clip box should be empty\n");
 
         trace("rcItem (%d,%d-%d,%d)\n", dis->rcItem.left, dis->rcItem.top,
                dis->rcItem.right, dis->rcItem.bottom);
@@ -456,18 +458,18 @@ static void test_itemfrompoint(void)
     HWND hList = CreateWindow( "ListBox", "list test",
                                WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT,
                                1, 1, 600, 100, NULL, NULL, NULL, NULL );
-    LONG r, id;
+    ULONG r, id;
     RECT rc;
 
-    /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000 */
+    /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */
     r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 ));
-    ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r );
+    ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
 
     r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 ));
-    ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r );
+    ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
 
     r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 ));
-    ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r );
+    ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r );
 
     id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi");
     ok( id == 0, "item id wrong\n");
@@ -478,7 +480,8 @@ static void test_itemfrompoint(void)
     ok( r == 0x1, "ret %x\n", r );
 
     r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 ));
-    ok( r == 0x10001, "ret %x\n", r );
+    ok( r == 0x10001 || broken(r == 1), /* nt4 */
+        "ret %x\n", r );
 
     /* Resize control so that below assertions about sizes are valid */
     r = SendMessage( hList, LB_GETITEMRECT, 0, (LPARAM)&rc);
@@ -515,16 +518,20 @@ static void test_itemfrompoint(void)
     ok( r == 1, "ret %x\n", r);
 
     r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) );
-    ok( r == 0x10001, "ret %x\n", r );
+    ok( r == 0x10001 || broken(r == 1), /* nt4 */
+        "ret %x\n", r );
 
     r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) );
-    ok( r == 0x10001, "ret %x\n", r );
+    ok( r == 0x10001 || broken(r == 1), /* nt4 */
+        "ret %x\n", r );
 
     r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) );
-    ok( r == 0x10005, "item %x\n", r );
+    ok( r == 0x10005 || broken(r == 5), /* nt4 */
+        "item %x\n", r );
 
     r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) );
-    ok( r == 0x10005, "item %x\n", r );
+    ok( r == 0x10005 || broken(r == 5), /* nt4 */
+        "item %x\n", r );
 
     DestroyWindow( hList );
 }
@@ -550,13 +557,14 @@ static void test_listbox_item_data(void)
     DestroyWindow( hList );
 }
 
-static void test_listbox_LB_DIR()
+static void test_listbox_LB_DIR(void)
 {
     HWND hList;
     int res, itemCount;
     int itemCount_justFiles;
     int itemCount_justDrives;
     int itemCount_allFiles;
+    int itemCount_allDirs;
     int i;
     char pathBuffer[MAX_PATH];
     char * p;
@@ -582,6 +590,11 @@ static void test_listbox_LB_DIR()
     strcpy(pathBuffer, "*");
     SendMessage(hList, LB_RESETCONTENT, 0, 0);
     res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
+    if (res == -1)  /* "*" wildcard doesn't work on win9x */
+    {
+        strcpy(pathBuffer, "*.*");
+        res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer);
+    }
     ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError());
 
     /* There should be some content in the listbox */
@@ -637,15 +650,22 @@ static void test_listbox_LB_DIR()
     strcpy(pathBuffer, "*");
     SendMessage(hList, LB_RESETCONTENT, 0, 0);
     res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
+    if (res == -1 || res <= itemCount_allFiles)  /* "*" wildcard doesn't work on win9x */
+    {
+        strcpy(pathBuffer, "*.*");
+        SendMessage(hList, LB_RESETCONTENT, 0, 0);
+        res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer);
+    }
     ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError());
 
     /* There should be some content in the listbox.
      * All files plus "[..]"
      */
     itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_allFiles + 1,
-        "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected %d\n",
-        itemCount, itemCount_allFiles + 1);
+    itemCount_allDirs = itemCount - itemCount_allFiles;
+    ok (itemCount > itemCount_allFiles,
+        "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n",
+        itemCount, itemCount_allFiles);
     ok(res + 1 == itemCount,
         "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n",
         itemCount - 1, res);
@@ -694,7 +714,7 @@ static void test_listbox_LB_DIR()
     strcpy(pathBuffer, "*");
     SendMessage(hList, LB_RESETCONTENT, 0, 0);
     res = SendMessage(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
-    ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *)  failed - 0x%08x\n", GetLastError());
+    ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *)  failed - 0x%08x\n", GetLastError());
 
     /* There should be some content in the listbox. In particular, there should
      * be at least one element before, since the string "[-c-]" should
@@ -749,10 +769,11 @@ static void test_listbox_LB_DIR()
      * been added.
      */
     itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justDrives + itemCount_allFiles,
-        "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n",
+    ok (itemCount == itemCount_justDrives + itemCount_allFiles ||
+        broken(itemCount == itemCount_justDrives),  /* "*" wildcard broken on win9x */
+        "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n",
         itemCount, itemCount_justDrives + itemCount_allFiles);
-    ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n");
+    ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n");
 
     /* This tests behavior when no files match the wildcard */
     strcpy(pathBuffer, BAD_EXTENSION);
@@ -810,9 +831,10 @@ static void test_listbox_LB_DIR()
      * be exactly the number of plain files, plus the number of mapped drives.
      */
     itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_allFiles + itemCount_justDrives + 1,
+    ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs ||
+        broken(itemCount == itemCount_justDrives + itemCount_allDirs), /* "*" wildcard broken on win9x */
         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
-        itemCount, itemCount_allFiles + itemCount_justDrives + 1);
+        itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs);
     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n");
 
     /* Every single item in the control should start with a w and end in .c,
@@ -879,18 +901,20 @@ static void test_listbox_LB_DIR()
     strcpy(pathBuffer, "*");
     SendMessage(hList, LB_RESETCONTENT, 0, 0);
     res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
-    ok (res == 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError());
+    ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError());
 
-    /* There should be exactly one element: "[..]" */
     itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
-    ok (itemCount == 1,
+    ok (itemCount == itemCount_allDirs,
         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
-        itemCount, 1);
+        itemCount, itemCount_allDirs);
     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
 
-    memset(pathBuffer, 0, MAX_PATH);
-    SendMessage(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
-    ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
+    if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3)  /* there's no [..] in drive root */
+    {
+        memset(pathBuffer, 0, MAX_PATH);
+        SendMessage(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
+        ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
+    }
 
     /* This tests behavior when no files match the wildcard */
     strcpy(pathBuffer, BAD_EXTENSION);
@@ -923,9 +947,9 @@ static void test_listbox_LB_DIR()
 
     /* There should be no plain files on the listbox */
     itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justDrives + 1,
+    ok (itemCount == itemCount_justDrives + itemCount_allDirs,
         "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
-        itemCount, itemCount_justDrives + 1);
+        itemCount, itemCount_justDrives + itemCount_allDirs);
     ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n");
 
     for (i = 0; i < itemCount; i++) {
@@ -936,7 +960,8 @@ static void test_listbox_LB_DIR()
         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
         } else {
-            ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit expected [..]\n", i, pathBuffer);
+            ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
+                "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
         }
     }
 
@@ -954,7 +979,7 @@ static void test_listbox_LB_DIR()
     strcpy(pathBuffer, "w*.c");
     SendMessage(hList, LB_RESETCONTENT, 0, 0);
     res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer);
-    ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
+    ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError());
 
     /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */
     itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0);
@@ -1046,6 +1071,7 @@ static void test_listbox_dlgdir(void)
     HINSTANCE hInst;
     HWND hWnd;
     int res, itemCount;
+    int itemCount_allDirs;
     int itemCount_justFiles;
     int itemCount_justDrives;
     int i;
@@ -1125,13 +1151,14 @@ static void test_listbox_dlgdir(void)
     ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError());
 
     /* There should be some content in the listbox. In particular, there should
-     * be exactly one more element than before, since the string "[..]" should
+     * be exactly more elements than before, since the directories should
      * have been added.
      */
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justFiles + 1,
-        "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected %d\n",
-        itemCount, itemCount_justFiles + 1);
+    itemCount_allDirs = itemCount - itemCount_justFiles;
+    ok (itemCount >= itemCount_justFiles,
+        "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n",
+        itemCount, itemCount_justFiles);
 
     /* Every single item in the control should start with a w and end in .c,
      * except for the "[..]" string, which should appear exactly as it is.
@@ -1140,7 +1167,7 @@ static void test_listbox_dlgdir(void)
         memset(pathBuffer, 0, MAX_PATH);
         SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
         p = pathBuffer + strlen(pathBuffer);
-        ok( !strcmp(pathBuffer, "[..]") ||
+        ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
             ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
             (*(p-1) == 'c' || *(p-1) == 'C') &&
             (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
@@ -1153,13 +1180,15 @@ static void test_listbox_dlgdir(void)
     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res);
 
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == 1, "DlgDirList() incorrectly filled the listbox! (expected 1 got %d)\n",
-        itemCount);
+    ok (itemCount == itemCount_allDirs,
+        "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
+        itemCount_allDirs, itemCount);
     for (i = 0; i < itemCount; i++) {
         memset(pathBuffer, 0, MAX_PATH);
         SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer);
         p = pathBuffer + strlen(pathBuffer);
-        ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit requested [..]\n", i, pathBuffer);
+        ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
+            "Element %d (%s) does not fit requested [...]\n", i, pathBuffer);
     }
 
 
@@ -1216,9 +1245,9 @@ static void test_listbox_dlgdir(void)
      * plus one "[..]"
      */
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justFiles + itemCount_justDrives + 1,
+    ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs,
         "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n",
-        itemCount, itemCount_justFiles + itemCount_justDrives + 1);
+        itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs);
 
     /* Every single item in the control should start with a w and end in .c,
      * except for the "[..]" string, which should appear exactly as it is,
@@ -1232,7 +1261,7 @@ static void test_listbox_dlgdir(void)
         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
         } else {
-            ok( !strcmp(pathBuffer, "[..]") ||
+            ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') ||
                 ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') &&
                 (*(p-1) == 'c' || *(p-1) == 'C') &&
                 (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer);
@@ -1246,9 +1275,9 @@ static void test_listbox_dlgdir(void)
     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res);
 
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justDrives + 1,
+    ok (itemCount == itemCount_justDrives + itemCount_allDirs,
         "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n",
-        itemCount_justDrives + 1, itemCount);
+        itemCount_justDrives + itemCount_allDirs, itemCount);
 
 
 
@@ -1260,14 +1289,16 @@ static void test_listbox_dlgdir(void)
 
     /* There should be exactly one element: "[..]" */
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == 1,
+    ok (itemCount == itemCount_allDirs,
         "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
-        itemCount, 1);
-
-    memset(pathBuffer, 0, MAX_PATH);
-    SendMessage(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
-    ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
+        itemCount, itemCount_allDirs);
 
+    if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3)  /* there's no [..] in drive root */
+    {
+        memset(pathBuffer, 0, MAX_PATH);
+        SendMessage(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer);
+        ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n");
+    }
 
     /* Test behavior when no files match the wildcard */
     strcpy(pathBuffer, BAD_EXTENSION);
@@ -1276,7 +1307,7 @@ static void test_listbox_dlgdir(void)
     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
 
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == 1, "DlgDirList() incorrectly filled the listbox!\n");
+    ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n");
 
 
     /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */
@@ -1287,9 +1318,9 @@ static void test_listbox_dlgdir(void)
 
     /* There should be no plain files on the listbox */
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justDrives + 1,
+    ok (itemCount == itemCount_justDrives + itemCount_allDirs,
         "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n",
-        itemCount, itemCount_justDrives + 1);
+        itemCount, itemCount_justDrives + itemCount_allDirs);
 
     for (i = 0; i < itemCount; i++) {
         memset(pathBuffer, 0, MAX_PATH);
@@ -1299,7 +1330,8 @@ static void test_listbox_dlgdir(void)
         if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) {
             ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter);
         } else {
-            ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit expected [..]\n", i, pathBuffer);
+            ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']',
+                "Element %d (%s) does not fit expected [...]\n", i, pathBuffer);
         }
     }
 
@@ -1310,7 +1342,8 @@ static void test_listbox_dlgdir(void)
     ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res);
 
     itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0);
-    ok (itemCount == itemCount_justDrives + 1, "DlgDirList() incorrectly filled the listbox!\n");
+    ok (itemCount == itemCount_justDrives + itemCount_allDirs,
+        "DlgDirList() incorrectly filled the listbox!\n");
 
 
     /* Now test DlgDirSelectEx() in normal operation */
index 1aa2eb6..adc9410 100755 (executable)
@@ -57,6 +57,33 @@ static void init_function_pointers(void)
 #undef GET_PROC
 }
 
+static BOOL correct_behavior(void)
+{
+    HMENU hmenu;
+    MENUITEMINFO info;
+    BOOL rc;
+
+    hmenu = CreateMenu();
+
+    memset(&info, 0, sizeof(MENUITEMINFO));
+    info.cbSize= sizeof(MENUITEMINFO);
+    SetLastError(0xdeadbeef);
+    rc = GetMenuItemInfo(hmenu, 0, TRUE, &info);
+    /* Win9x  : 0xdeadbeef
+     * NT4    : ERROR_INVALID_PARAMETER
+     * >= W2K : ERROR_MENU_ITEM_NOT_FOUND
+     */
+    if (!rc && GetLastError() != ERROR_MENU_ITEM_NOT_FOUND)
+    {
+        win_skip("NT4 and below can't handle a bigger MENUITEMINFO struct\n");
+        DestroyMenu(hmenu);
+        return FALSE;
+    }
+
+    DestroyMenu(hmenu);
+    return TRUE;
+}
+
 static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 {
     switch (msg)
@@ -357,7 +384,8 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt,
     MOD_GotDrawItemMsg = FALSE;
     mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE;
     mii.fType = 0;
-    mii.fState = MF_CHECKED;
+    /* check the menu item unless MNS_CHECKORBMP is set */
+    mii.fState = (mnuopt != 2 ? MFS_CHECKED : MFS_UNCHECKED);
     mii.dwItemData =0;
     MODsizes[0] = bmpsize;
     hastab = 0;
@@ -447,8 +475,14 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt,
     if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) {
         /* check the position of the bitmap */
         /* horizontal */
-        expect = ispop ? (4 + ( mnuopt  ? 0 : GetSystemMetrics(SM_CXMENUCHECK)))
-            : 3;
+        if (!ispop)
+            expect = 3;
+        else if (mnuopt == 0)
+            expect = 4 + GetSystemMetrics(SM_CXMENUCHECK);
+        else if (mnuopt == 1)
+            expect = 4;
+        else /* mnuopt == 2 */
+            expect = 2;
         ok( expect == MOD_rc[0].left,
                 "bitmap left is %d expected %d\n", MOD_rc[0].left, expect);
         failed = failed || !(expect == MOD_rc[0].left);
@@ -1691,7 +1725,7 @@ static struct menu_mouse_tests_s {
 static void send_key(WORD wVk)
 {
     TEST_INPUT i[2];
-    memset(&i, 0, 2*sizeof(INPUT));
+    memset(i, 0, sizeof(i));
     i[0].type = i[1].type = INPUT_KEYBOARD;
     i[0].u.ki.wVk = i[1].u.ki.wVk = wVk;
     i[1].u.ki.dwFlags = KEYEVENTF_KEYUP;
@@ -1706,10 +1740,10 @@ static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi)
     RECT r;
     int screen_w = GetSystemMetrics(SM_CXSCREEN);
     int screen_h = GetSystemMetrics(SM_CYSCREEN);
+    BOOL ret = GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
+    if(!ret) return;
 
-    GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r);
-
-    memset(&i, 0, 3*sizeof(INPUT));
+    memset(i, 0, sizeof(i));
     i[0].type = i[1].type = i[2].type = INPUT_MOUSE;
     i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx
             = ((r.left + 5) * 65535) / screen_w;
@@ -1785,6 +1819,7 @@ static void test_menu_input(void) {
     WNDCLASSA  wclass;
     HINSTANCE hInstance = GetModuleHandleA( NULL );
     HANDLE hThread, hWnd;
+    DWORD tid;
 
     wclass.lpszClassName = "MenuTestClass";
     wclass.style         = CS_HREDRAW | CS_VREDRAW;
@@ -1820,7 +1855,7 @@ static void test_menu_input(void) {
     ShowWindow(hWnd, SW_SHOW);
     UpdateWindow(hWnd);
 
-    hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL);
+    hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid);
     while(1)
     {
         if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50))
@@ -1997,9 +2032,10 @@ static void test_menu_hilitemenuitem( void )
 static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type,
                              UINT checked_state)
 {
-    UINT i, count;
+    INT i, count;
 
     count = GetMenuItemCount(hmenu);
+    ok (count != -1, "GetMenuItemCount returned -1\n");
 
     for (i = 0; i < count; i++)
     {
@@ -2140,7 +2176,7 @@ static void test_menu_resource_layout(void)
         { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 8, "" }
     };
     HMENU hmenu;
-    UINT count, i;
+    INT count, i;
     BOOL ret;
 
     hmenu = LoadMenuIndirect(&menu_template);
@@ -2342,13 +2378,23 @@ START_TEST(menu)
 {
     init_function_pointers();
 
+    /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't
+     * handle that.
+     */
+    if (correct_behavior())
+    {
+        test_menu_add_string();
+        test_menu_iteminfo();
+        test_menu_search_bycommand();
+        test_CheckMenuRadioItem();
+        test_menu_resource_layout();
+        test_InsertMenu();
+    }
+
     register_menu_check_class();
 
     test_menu_locked_by_window();
     test_menu_ownerdraw();
-    test_menu_add_string();
-    test_menu_iteminfo();
-    test_menu_search_bycommand();
     test_menu_bmp_and_string();
 
     if( !pSendInput)
@@ -2358,7 +2404,4 @@ START_TEST(menu)
     test_menu_flags();
 
     test_menu_hilitemenuitem();
-    test_CheckMenuRadioItem();
-    test_menu_resource_layout();
-    test_InsertMenu();
 }
index a723dd1..3d03596 100644 (file)
@@ -2,6 +2,7 @@
  * Unit tests for monitor APIs
  *
  * Copyright 2005 Huw Davies
+ * Copyright 2008 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -61,7 +62,7 @@ static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc,
     mi.cbSize = sizeof(mi);
 
     ok(pGetMonitorInfoA(hmon, (MONITORINFO*)&mi), "GetMonitorInfo failed\n");
-    if(mi.dwFlags == MONITORINFOF_PRIMARY)
+    if (mi.dwFlags & MONITORINFOF_PRIMARY)
         strcpy(primary, mi.szDevice);
 
     return TRUE;
@@ -73,15 +74,20 @@ static void test_enumdisplaydevices(void)
     char primary_device_name[32];
     char primary_monitor_device_name[32];
     DWORD primary_num = -1, num = 0;
+    BOOL ret;
+
+    if (!pEnumDisplayDevicesA)
+    {
+        skip("EnumDisplayDevicesA is not available\n");
+        return;
+    }
 
     dd.cb = sizeof(dd);
-    if(pEnumDisplayDevicesA == NULL) return;
     while(1)
     {
         BOOL ret;
         HDC dc;
         ret = pEnumDisplayDevicesA(NULL, num, &dd, 0);
-        ok(ret || num != 0, "EnumDisplayDevices fails with num == 0\n");
         if(!ret) break;
         if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
         {
@@ -97,22 +103,25 @@ static void test_enumdisplaydevices(void)
         }
         num++;
     }
-    ok(primary_num != -1, "Didn't get the primary device\n");
 
-    if(pEnumDisplayMonitors && pGetMonitorInfoA) {
-        ok(pEnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)primary_monitor_device_name),
-           "EnumDisplayMonitors failed\n");
-
-        ok(!strcmp(primary_monitor_device_name, primary_device_name),
-           "monitor device name %s, device name %s\n", primary_monitor_device_name,
-           primary_device_name);
+    if (primary_num == -1 || !pEnumDisplayMonitors || !pGetMonitorInfoA)
+    {
+        win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n");
+        return;
     }
+
+    primary_monitor_device_name[0] = 0;
+    ret = pEnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)primary_monitor_device_name);
+    ok(ret, "EnumDisplayMonitors failed\n");
+    ok(!strcmp(primary_monitor_device_name, primary_device_name),
+       "monitor device name %s, device name %s\n", primary_monitor_device_name,
+       primary_device_name);
 }
 
 struct vid_mode
 {
     DWORD w, h, bpp, freq, fields;
-    LONG success;
+    BOOL must_succeed;
 };
 
 static const struct vid_mode vid_modes_test[] = {
@@ -120,18 +129,20 @@ static const struct vid_mode vid_modes_test[] = {
     {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT |                 DM_DISPLAYFREQUENCY, 1},
     {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL                      , 1},
     {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT                                      , 1},
-    {640, 480, 0, 0,                                DM_BITSPERPEL                      , 1},
-    {640, 480, 0, 0,                                                DM_DISPLAYFREQUENCY, 1},
+    {640, 480, 0, 0,                                DM_BITSPERPEL                      , 0},
+    {640, 480, 0, 0,                                                DM_DISPLAYFREQUENCY, 0},
 
-    {0, 0, 0, 0, DM_PELSWIDTH, 1},
-    {0, 0, 0, 0, DM_PELSHEIGHT, 1},
+    {0, 0, 0, 0, DM_PELSWIDTH, 0},
+    {0, 0, 0, 0, DM_PELSHEIGHT, 0},
 
     {640, 480, 0, 0, DM_PELSWIDTH, 0},
     {640, 480, 0, 0, DM_PELSHEIGHT, 0},
     {  0, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0},
     {640,   0, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0},
 
-    {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0},
+    /* the following test succeeds under XP SP3
+    {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0}
+    */
 };
 #define vid_modes_cnt (sizeof(vid_modes_test) / sizeof(vid_modes_test[0]))
 
@@ -155,6 +166,45 @@ static void test_ChangeDisplaySettingsEx(void)
 
     width = dm.dmPelsWidth;
 
+    dm.dmDriverExtra = 1;
+    res = ChangeDisplaySettingsA(&dm, CDS_TEST);
+    ok(res == DISP_CHANGE_SUCCESSFUL,
+       "ChangeDisplaySettingsA returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res);
+    ok(dm.dmDriverExtra == 0 || broken(dm.dmDriverExtra == 1) /* win9x */,
+       "ChangeDisplaySettingsA didn't reset dmDriverExtra to 0\n");
+
+    /* crashes under XP SP3 for large dmDriverExtra values */
+    dm.dmDriverExtra = 1;
+    res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL);
+    ok(res == DISP_CHANGE_SUCCESSFUL,
+       "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_BADMODE\n", res);
+    ok(dm.dmDriverExtra == 1, "ChangeDisplaySettingsExA shouldn't reset dmDriverExtra to 0\n");
+
+    memset(&dmW, 0, sizeof(dmW));
+    dmW.dmSize = sizeof(dmW);
+    dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+    dmW.dmPelsWidth = dm.dmPelsWidth;
+    dmW.dmPelsHeight = dm.dmPelsHeight;
+    dmW.dmDriverExtra = 1;
+    SetLastError(0xdeadbeef);
+    res = ChangeDisplaySettingsW(&dmW, CDS_TEST);
+    if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        ok(res == DISP_CHANGE_SUCCESSFUL,
+           "ChangeDisplaySettingsW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res);
+        ok(dmW.dmDriverExtra == 0, "ChangeDisplaySettingsW didn't reset dmDriverExtra to 0\n");
+    }
+
+    /* Apparently XP treats dmDriverExtra being != 0 as an error */
+    dmW.dmDriverExtra = 1;
+    res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL);
+    if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        ok(res == DISP_CHANGE_SUCCESSFUL,
+           "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_BADMODE\n", res);
+        ok(dmW.dmDriverExtra == 1, "ChangeDisplaySettingsExW shouldn't reset dmDriverExtra to 0\n");
+    }
+
     /* the following 2 tests show that dm.dmSize being 0 is invalid, but
      * ChangeDisplaySettingsExA still reports success.
      */
@@ -162,8 +212,10 @@ static void test_ChangeDisplaySettingsEx(void)
     dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
     dm.dmPelsWidth = width;
     res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL);
-    ok(res == DISP_CHANGE_SUCCESSFUL,
-       "ChangeDisplaySettingsExA returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res);
+    ok(res == DISP_CHANGE_SUCCESSFUL ||
+       res == DISP_CHANGE_BADMODE || /* Win98, WinMe */
+       res == DISP_CHANGE_FAILED, /* NT4 */
+       "ChangeDisplaySettingsExA returned unexpected %d\n", res);
 
     memset(&dmW, 0, sizeof(dmW));
     dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
@@ -171,8 +223,10 @@ static void test_ChangeDisplaySettingsEx(void)
     SetLastError(0xdeadbeef);
     res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL);
     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
-        ok(res == DISP_CHANGE_FAILED,
-           "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_FAILED\n", res);
+        ok(res == DISP_CHANGE_FAILED ||
+           res == DISP_CHANGE_BADPARAM ||  /* NT4 */
+           res == DISP_CHANGE_BADMODE /* XP SP3 */,
+           "ChangeDisplaySettingsExW returned %d\n", res);
 
     memset(&dm, 0, sizeof(dm));
     dm.dmSize = sizeof(dm);
@@ -184,10 +238,10 @@ static void test_ChangeDisplaySettingsEx(void)
         dm.dmBitsPerPel       = vid_modes_test[i].bpp;
         dm.dmDisplayFrequency = vid_modes_test[i].freq;
         dm.dmFields           = vid_modes_test[i].fields;
-        res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_FULLSCREEN, NULL);
-        ok(vid_modes_test[i].success ?
+        res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL);
+        ok(vid_modes_test[i].must_succeed ?
            (res == DISP_CHANGE_SUCCESSFUL) :
-           (res == DISP_CHANGE_BADMODE || res == DISP_CHANGE_BADPARAM),
+           (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_BADMODE || res == DISP_CHANGE_BADPARAM),
            "Unexpected ChangeDisplaySettingsEx() return code for resolution[%d]: %d\n", i, res);
 
         if (res == DISP_CHANGE_SUCCESSFUL)
@@ -195,6 +249,8 @@ static void test_ChangeDisplaySettingsEx(void)
             RECT r, r1, virt;
 
             SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
+            if (IsRectEmpty(&virt))  /* NT4 doesn't have SM_CX/YVIRTUALSCREEN */
+                SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
             OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN));
 
             /* Resolution change resets clip rect */
@@ -214,7 +270,10 @@ static void test_ChangeDisplaySettingsEx(void)
             SetRect(&r1, virt.left - 10, virt.top - 10, virt.right + 20, virt.bottom + 20);
             ok(ClipCursor(&r1), "ClipCursor() failed\n");
             ok(GetClipCursor(&r), "GetClipCursor() failed\n");
-            ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n", r.left, r.top, r.right, r.bottom);
+            ok(EqualRect(&r, &virt) ||
+               broken(EqualRect(&r, &r1)) /* win9x */,
+               "Invalid clip rect: (%d %d) x (%d %d)\n", r.left, r.top, r.right, r.bottom);
+            ClipCursor(&virt);
         }
     }
     res = pChangeDisplaySettingsExA(NULL, NULL, NULL, CDS_RESET, NULL);
@@ -226,6 +285,12 @@ static void test_monitors(void)
     HMONITOR monitor, primary;
     POINT pt;
 
+    if (!pMonitorFromPoint || !pMonitorFromWindow)
+    {
+        skip("MonitorFromPoint or MonitorFromWindow are not available\n");
+        return;
+    }
+
     pt.x = pt.y = 0;
     primary = pMonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY );
     ok( primary != 0, "couldn't get primary monitor\n" );
@@ -238,15 +303,96 @@ static void test_monitors(void)
     ok( monitor == primary, "got %p, should get primary %p for MONITOR_DEFAULTTONEAREST\n", monitor, primary );
 }
 
+static BOOL CALLBACK find_primary_mon(HMONITOR hmon, HDC hdc, LPRECT rc, LPARAM lp)
+{
+    MONITORINFO mi;
+    BOOL ret;
+
+    mi.cbSize = sizeof(mi);
+    ret = pGetMonitorInfoA(hmon, &mi);
+    ok(ret, "GetMonitorInfo failed\n");
+    if (mi.dwFlags & MONITORINFOF_PRIMARY)
+    {
+        *(HMONITOR *)lp = hmon;
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static void test_work_area(void)
+{
+    HMONITOR hmon;
+    MONITORINFO mi;
+    RECT rc_work, rc_normal;
+    HWND hwnd;
+    WINDOWPLACEMENT wp;
+    BOOL ret;
+
+    if (!pEnumDisplayMonitors || !pGetMonitorInfoA)
+    {
+        skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n");
+        return;
+    }
+
+    hmon = 0;
+    ret = pEnumDisplayMonitors(NULL, NULL, find_primary_mon, (LPARAM)&hmon);
+    ok(!ret && hmon != 0, "Failed to find primary monitor\n");
+
+    mi.cbSize = sizeof(mi);
+    SetLastError(0xdeadbeef);
+    ret = pGetMonitorInfoA(hmon, &mi);
+    ok(ret, "GetMonitorInfo error %u\n", GetLastError());
+    ok(mi.dwFlags & MONITORINFOF_PRIMARY, "not a primary monitor\n");
+    trace("primary monitor (%d,%d-%d,%d)\n",
+        mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom);
+
+    SetLastError(0xdeadbeef);
+    ret = SystemParametersInfo(SPI_GETWORKAREA, 0, &rc_work, 0);
+    ok(ret, "SystemParametersInfo error %u\n", GetLastError());
+    trace("work area (%d,%d-%d,%d)\n", rc_work.left, rc_work.top, rc_work.right, rc_work.bottom);
+    ok(EqualRect(&rc_work, &mi.rcWork), "work area is different\n");
+
+    hwnd = CreateWindowEx(0, "static", NULL, WS_OVERLAPPEDWINDOW|WS_VISIBLE,100,100,10,10,0,0,0,NULL);
+    ok(hwnd != 0, "CreateWindowEx failed\n");
+
+    ret = GetWindowRect(hwnd, &rc_normal);
+    ok(ret, "GetWindowRect failed\n");
+    trace("normal (%d,%d-%d,%d)\n", rc_normal.left, rc_normal.top, rc_normal.right, rc_normal.bottom);
+
+    wp.length = sizeof(wp);
+    ret = GetWindowPlacement(hwnd, &wp);
+    ok(ret, "GetWindowPlacement failed\n");
+    trace("min: %d,%d max %d,%d normal %d,%d-%d,%d\n",
+          wp.ptMinPosition.x, wp.ptMinPosition.y,
+          wp.ptMaxPosition.x, wp.ptMaxPosition.y,
+          wp.rcNormalPosition.left, wp.rcNormalPosition.top,
+          wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
+    OffsetRect(&wp.rcNormalPosition, rc_work.left, rc_work.top);
+    if (!EqualRect(&mi.rcMonitor, &mi.rcWork)) /* FIXME: remove once Wine is fixed */
+        todo_wine ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n");
+    else
+        ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n");
+
+    SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
+
+    wp.length = sizeof(wp);
+    ret = GetWindowPlacement(hwnd, &wp);
+    ok(ret, "GetWindowPlacement failed\n");
+    trace("min: %d,%d max %d,%d normal %d,%d-%d,%d\n",
+          wp.ptMinPosition.x, wp.ptMinPosition.y,
+          wp.ptMaxPosition.x, wp.ptMaxPosition.y,
+          wp.rcNormalPosition.left, wp.rcNormalPosition.top,
+          wp.rcNormalPosition.right, wp.rcNormalPosition.bottom);
+    ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n");
+
+    DestroyWindow(hwnd);
+}
 
 START_TEST(monitor)
 {
     init_function_pointers();
     test_enumdisplaydevices();
-    if (winetest_interactive)
-        test_ChangeDisplaySettingsEx();
-    if (pMonitorFromPoint && pMonitorFromWindow)
-        test_monitors();
-    else
-        skip("MonitorFromPoint and/or MonitorFromWindow are not available\n");
+    test_ChangeDisplaySettingsEx();
+    test_monitors();
+    test_work_area();
 }
index 5c66f0c..16ce1c2 100755 (executable)
@@ -141,6 +141,8 @@ static const struct message WmSWP_ShowOverlappedSeq[] = {
     { WM_ERASEBKGND, sent|optional },
     { HCBT_ACTIVATE, hook },
     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_NOTIFYFORMAT, sent|optional },
+    { WM_QUERYUISTATE, sent|optional },
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
     { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
     { WM_ACTIVATEAPP, sent|wparam, 1 },
@@ -152,15 +154,20 @@ static const struct message WmSWP_ShowOverlappedSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ERASEBKGND, sent|optional },
     /* Win9x adds SWP_NOZORDER below */
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_GETTEXT, sent|optional },
     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_ERASEBKGND, sent|optional },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_PAINT, sent|optional },
+    { WM_NCPAINT, sent|beginpaint|optional },
+    { WM_ERASEBKGND, sent|beginpaint|optional },
     { 0 }
 };
 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
@@ -219,6 +226,9 @@ static const struct message WmSWP_ResizePopupSeq[] = {
  */
 static const struct message WmSWP_MoveSeq[] = {
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
+    { WM_NCPAINT, sent|optional },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent|optional },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
     { WM_MOVE, sent|defwinproc|wparam, 0 },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
@@ -229,13 +239,13 @@ static const struct message WmSWP_MoveSeq[] = {
  * SWP_NOZORDER is stripped by the logging code
  */
 static const struct message WmSWP_ResizeNoZOrder[] = {
-    { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ },
+    { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
     { WM_GETMINMAXINFO, sent|defwinproc },
     { WM_NCCALCSIZE, sent|wparam, 1 },
     { WM_NCPAINT, sent },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
-    { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE },
     { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
     { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
     { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
@@ -314,12 +324,12 @@ static const struct message WmSwitchNotMaximizedChild[] = {
     /* Activate 2nd MDI child */
     { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
-    { WM_SETVISIBLE, hook }, /* in the 1st MDI child */
+    { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
     { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
     { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
     { WM_SETFOCUS, sent, 0 }, /* in the  MDI client */
-    { WM_SETVISIBLE, hook },
+    { HCBT_SETFOCUS, hook },
     { WM_KILLFOCUS, sent }, /* in the  MDI client */
     { WM_IME_SETCONTEXT, sent|optional }, /* in the  MDI client */
     { WM_IME_SETCONTEXT, sent|defwinproc|optional  }, /* in the 1st MDI child */
@@ -395,7 +405,7 @@ static const struct message WmShowOverlappedSeq[] = {
     { HCBT_ACTIVATE, hook },
     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_ACTIVATEAPP, sent|wparam, 1 },
     { WM_NCACTIVATE, sent|wparam, 1 },
@@ -406,12 +416,14 @@ static const struct message WmShowOverlappedSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ERASEBKGND, sent|optional },
     /* Win9x adds SWP_NOZORDER below */
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { WM_NCCALCSIZE, sent|optional },
+    { WM_GETTEXT, sent|optional },
     { WM_NCPAINT, sent|optional },
     { WM_ERASEBKGND, sent|optional },
 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
@@ -421,6 +433,8 @@ static const struct message WmShowOverlappedSeq[] = {
     { WM_SIZE, sent },
     { WM_MOVE, sent },
 #endif
+    { WM_PAINT, sent|optional },
+    { WM_NCPAINT, sent|beginpaint|optional },
     { 0 }
 };
 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
@@ -434,7 +448,7 @@ static const struct message WmShowMaxOverlappedSeq[] = {
     { HCBT_ACTIVATE, hook },
     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
     { WM_ACTIVATEAPP, sent|wparam, 1 },
     { WM_NCACTIVATE, sent|wparam, 1 },
     { WM_GETTEXT, sent|defwinproc|optional },
@@ -444,6 +458,7 @@ static const struct message WmShowMaxOverlappedSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ERASEBKGND, sent|optional },
@@ -451,11 +466,72 @@ static const struct message WmShowMaxOverlappedSeq[] = {
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
     { WM_MOVE, sent|defwinproc },
     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
+    { WM_GETTEXT, sent|optional },
     { WM_NCCALCSIZE, sent|optional },
     { WM_NCPAINT, sent|optional },
     { WM_ERASEBKGND, sent|optional },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_PAINT, sent|optional },
+    { WM_NCPAINT, sent|beginpaint|optional },
+    { WM_ERASEBKGND, sent|beginpaint|optional },
+    { 0 }
+};
+/* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
+static const struct message WmShowRestoreMaxOverlappedSeq[] = {
+    { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
+    { WM_GETTEXT, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
+    { WM_GETMINMAXINFO, sent|defwinproc },
+    { WM_NCCALCSIZE, sent|wparam, TRUE },
+    { WM_NCPAINT, sent|optional },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
+    { WM_MOVE, sent|defwinproc|optional },
+    { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
+    { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
+    { WM_NCPAINT, sent|optional },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_PAINT, sent|optional },
+    { WM_NCPAINT, sent|beginpaint|optional },
+    { WM_ERASEBKGND, sent|beginpaint|optional },
+    { 0 }
+};
+/* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
+static const struct message WmShowRestoreMinOverlappedSeq[] = {
+    { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
+    { WM_QUERYOPEN, sent|optional },
+    { WM_GETTEXT, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
+    { WM_GETMINMAXINFO, sent|defwinproc },
+    { WM_NCCALCSIZE, sent|wparam, TRUE },
+    { HCBT_ACTIVATE, hook },
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { HCBT_SETFOCUS, hook },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
+    { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
+    { WM_NCPAINT, sent|wparam|optional, 1 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent },
+    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
+    { WM_MOVE, sent|defwinproc },
+    { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
+    { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
+    { WM_NCPAINT, sent|wparam|optional, 1 },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|optional },
+    { WM_PAINT, sent|optional },
+    { WM_NCPAINT, sent|beginpaint|optional },
+    { WM_ERASEBKGND, sent|beginpaint|optional },
     { 0 }
 };
 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
@@ -471,7 +547,7 @@ static const struct message WmShowMinOverlappedSeq[] = {
     { WM_GETMINMAXINFO, sent|defwinproc },
     { WM_NCCALCSIZE, sent|wparam, TRUE },
     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
-    { WM_NCPAINT, sent },
+    { WM_NCPAINT, sent|optional },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_WINDOWPOSCHANGED, sent },
     { WM_MOVE, sent|defwinproc },
@@ -484,6 +560,9 @@ static const struct message WmShowMinOverlappedSeq[] = {
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ACTIVATE, sent },
     { WM_ACTIVATEAPP, sent|wparam, 0 },
+    { WM_PAINT, sent|optional },
+    { WM_NCPAINT, sent|beginpaint|optional },
+    { WM_ERASEBKGND, sent|beginpaint|optional },
     { 0 }
 };
 /* ShowWindow(SW_HIDE) for a visible overlapped window */
@@ -510,10 +589,10 @@ static const struct message WmDestroyOverlappedSeq[] = {
     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
     { 0x0090, sent|optional },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
-    { WM_NCACTIVATE, sent|wparam, 0 },
-    { WM_ACTIVATE, sent|wparam, 0 },
-    { WM_ACTIVATEAPP, sent|wparam, 0 },
-    { WM_KILLFOCUS, sent|wparam, 0 },
+    { WM_NCACTIVATE, sent|optional|wparam, 0 },
+    { WM_ACTIVATE, sent|optional|wparam, 0 },
+    { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
+    { WM_KILLFOCUS, sent|optional|wparam, 0 },
     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
     { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
@@ -545,6 +624,9 @@ static const struct message WmCreateMaxPopupSeq[] = {
     { 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_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
     { WM_ACTIVATEAPP, sent|wparam, 1 },
     { WM_NCACTIVATE, sent|wparam, 1 },
     { WM_ACTIVATE, sent|wparam, 1 },
@@ -553,6 +635,7 @@ static const struct message WmCreateMaxPopupSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_SYNCPAINT, sent|wparam|optional, 4 },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_ERASEBKGND, sent|optional },
@@ -597,9 +680,10 @@ static const struct message WmShowMaxPopupResizedSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_ERASEBKGND, sent|optional },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGED, sent },
     /* WinNT4.0 sends WM_MOVE */
     { WM_MOVE, sent|defwinproc|optional },
     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
@@ -625,6 +709,7 @@ static const struct message WmShowMaxPopupSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_SYNCPAINT, sent|wparam|optional, 4 },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_ERASEBKGND, sent|optional },
@@ -658,6 +743,7 @@ static const struct message WmCreatePopupSeq[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_GETTEXT, sent|optional },
     { WM_SYNCPAINT, sent|wparam|optional, 4 },
     { WM_NCPAINT, sent|wparam|optional, 1 },
     { WM_ERASEBKGND, sent|optional },
@@ -670,6 +756,7 @@ static const struct message WmShowVisMaxPopupSeq[] = {
     { WM_GETMINMAXINFO, sent },
     { WM_GETTEXT, sent|optional },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
+    { WM_GETTEXT, sent|optional },
     { WM_NCCALCSIZE, sent|wparam, TRUE },
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
     { WM_NCPAINT, sent|wparam|optional, 1 },
@@ -721,7 +808,7 @@ static const struct message WmShowVisiblePopupSeq_3[] = {
     { HCBT_ACTIVATE, hook },
     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
     { WM_NCACTIVATE, sent|wparam, 1 },
     { WM_ACTIVATE, sent|wparam, 1 },
     { HCBT_SETFOCUS, hook },
@@ -731,6 +818,7 @@ static const struct message WmShowVisiblePopupSeq_3[] = {
     { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|defwinproc },
+    { WM_GETTEXT, sent|optional },
     { 0 }
 };
 /* CreateWindow (for child window, not initially visible) */
@@ -846,6 +934,7 @@ static const struct message WmShowChildInvisibleParentSeq_1[] = {
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
     { WM_NCCALCSIZE, sent|wparam, 1 },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_CHILDACTIVATE, sent|optional },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
     { WM_MOVE, sent|defwinproc },
     { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED },
@@ -1081,6 +1170,12 @@ static const struct message WmCreateCustomDialogSeq[] = {
     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
     { WM_CREATE, sent },
     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_NOTIFYFORMAT, sent|optional },
+    { WM_QUERYUISTATE, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_GETMINMAXINFO, sent|optional },
+    { WM_NCCALCSIZE, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
     { WM_SHOWWINDOW, sent|wparam, 1 },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
@@ -1090,13 +1185,14 @@ static const struct message WmCreateCustomDialogSeq[] = {
 
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
 
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
 
     { WM_NCACTIVATE, sent|wparam, 1 },
     { WM_GETTEXT, sent|optional|defwinproc },
     { WM_GETTEXT, sent|optional|defwinproc },
     { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
     { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|optional },
     { WM_KILLFOCUS, sent|parent },
     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
@@ -1155,10 +1251,11 @@ static const struct message WmShowCustomDialogSeq[] = {
 
     { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
 
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
     { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
     { WM_NCACTIVATE, sent|wparam, 1 },
     { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|optional },
 
     { WM_KILLFOCUS, sent|parent },
     { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
@@ -1246,6 +1343,7 @@ static const struct message WmModalDialogSeq[] = {
     { WM_ACTIVATE, sent|wparam, 0 },
     { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
     { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
     { HCBT_SETFOCUS, hook },
     { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
@@ -1493,9 +1591,19 @@ static const struct message WmSHOWNAChildInvisParVis[] = {
 static const struct message WmSHOWNATopVisible[] = {
     { WM_SHOWWINDOW, sent|wparam, 1 },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+    { WM_NCPAINT, sent|wparam|optional, 1 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
     { 0 }
 };
 static const struct message WmSHOWNATopInvisible[] = {
+    { WM_NOTIFYFORMAT, sent|optional },
+    { WM_QUERYUISTATE, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_GETMINMAXINFO, sent|optional },
+    { WM_NCCALCSIZE, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
     { WM_SHOWWINDOW, sent|wparam, 1 },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
@@ -1516,10 +1624,13 @@ static int after_end_dialog, test_def_id;
 static int sequence_cnt, sequence_size;
 static struct message* sequence;
 static int log_all_parent_messages;
+static int paint_loop_done;
 
 /* user32 functions */
 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
+static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
+static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
@@ -1538,7 +1649,9 @@ static void init_procs(void)
     }
 
     GET_PROC(user32, GetAncestor)
+    GET_PROC(user32, GetMenuInfo)
     GET_PROC(user32, NotifyWinEvent)
+    GET_PROC(user32, SetMenuInfo)
     GET_PROC(user32, SetWinEventHook)
     GET_PROC(user32, TrackMouseEvent)
     GET_PROC(user32, UnhookWinEvent)
@@ -1583,7 +1696,7 @@ static void flush_events(void)
         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
         while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
         diff = time - GetTickCount();
-        min_timeout = 10;
+        min_timeout = 20;
     }
 }
 
@@ -1729,6 +1842,8 @@ static void ok_sequence_(const struct message *expected, const char *context, in
     flush_sequence();
 }
 
+#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
+
 /******************************** MDI test **********************************/
 
 /* CreateWindow for MDI frame window, initially visible */
@@ -1740,6 +1855,12 @@ static const struct message WmCreateMDIframeSeq[] = {
     { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
     { WM_CREATE, sent },
     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_NOTIFYFORMAT, sent|optional },
+    { WM_QUERYUISTATE, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_GETMINMAXINFO, sent|optional },
+    { WM_NCCALCSIZE, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
     { WM_SHOWWINDOW, sent|wparam, 1 },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
@@ -1769,10 +1890,10 @@ static const struct message WmCreateMDIframeSeq[] = {
 static const struct message WmDestroyMDIframeSeq[] = {
     { HCBT_DESTROYWND, hook },
     { 0x0090, sent|optional },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
     { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
     { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
@@ -1795,26 +1916,26 @@ static const struct message WmCreateMDIclientSeq[] = {
     { WM_MOVE, sent },
     { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
     { WM_SHOWWINDOW, sent|wparam, 1 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { 0 }
 };
 /* ShowWindow(SW_SHOW) for MDI client window */
 static const struct message WmShowMDIclientSeq[] = {
     { WM_SHOWWINDOW, sent|wparam, 1 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { 0 }
 };
 /* ShowWindow(SW_HIDE) for MDI client window */
 static const struct message WmHideMDIclientSeq[] = {
     { WM_SHOWWINDOW, sent|wparam, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { 0 }
 };
 /* DestroyWindow for MDI client window, initially visible */
@@ -1823,9 +1944,9 @@ static const struct message WmDestroyMDIclientSeq[] = {
     { 0x0090, sent|optional },
     { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
     { WM_SHOWWINDOW, sent|wparam, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
     { WM_DESTROY, sent },
     { WM_NCDESTROY, sent },
@@ -1918,10 +2039,10 @@ static const struct message WmDestroyMDIchildVisibleSeq[] = {
     { 0x0090, sent|optional },
     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
     { WM_SHOWWINDOW, sent|wparam, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
     { WM_ERASEBKGND, sent|parent|optional },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
 
     /* { WM_DESTROY, sent }
      * Win9x: message sequence terminates here.
@@ -2129,7 +2250,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
 
     { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
     { HCBT_SETFOCUS, hook },
-    { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
+    { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
@@ -2260,6 +2381,9 @@ static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
     { WM_CREATE, sent },
     { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
     { WM_SIZE, sent|wparam, SIZE_RESTORED },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE }, /* MDI frame */
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* MDI frame */
     { WM_MOVE, sent },
     { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
     { WM_GETMINMAXINFO, sent },
@@ -2469,12 +2593,12 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
 
      /* in MDI frame */
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
-    { WM_NCCALCSIZE, sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 },
     { 0x0093, sent|defwinproc|optional },
     { 0x0093, sent|defwinproc|optional },
     { 0x0093, sent|defwinproc|optional },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
     { 0x0093, sent|optional },
 
@@ -2534,10 +2658,10 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
     { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
 
     { WM_SHOWWINDOW, sent|wparam, 0 },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
     { WM_ERASEBKGND, sent|parent|optional },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
 
     { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
     { WM_DESTROY, sent },
@@ -2553,19 +2677,19 @@ static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
 
-    { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
-    { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
-    { HCBT_SETFOCUS, hook },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
+    { HCBT_SETFOCUS, hook|optional },
     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
-    { WM_SETFOCUS, sent }, /* in MDI client */
-    { HCBT_SETFOCUS, hook },
-    { WM_KILLFOCUS, sent }, /* in MDI client */
+    { WM_SETFOCUS, sent|optional }, /* in MDI client */
+    { HCBT_SETFOCUS, hook|optional },
+    { WM_KILLFOCUS, sent|optional }, /* in MDI client */
     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
-    { WM_SETFOCUS, sent|defwinproc },
-    { WM_MDIACTIVATE, sent|defwinproc },
+    { WM_SETFOCUS, sent|optional|defwinproc },
+    { WM_MDIACTIVATE, sent|optional|defwinproc },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
     { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
      /* in MDI frame */
@@ -2586,19 +2710,19 @@ static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
     { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
     { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
 
-    { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
-    { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
-    { HCBT_SETFOCUS, hook },
+    { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
+    { HCBT_SETFOCUS, hook|optional },
     { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
-    { WM_SETFOCUS, sent }, /* in MDI client */
-    { HCBT_SETFOCUS, hook },
-    { WM_KILLFOCUS, sent }, /* in MDI client */
+    { WM_SETFOCUS, sent|optional }, /* in MDI client */
+    { HCBT_SETFOCUS, hook|optional },
+    { WM_KILLFOCUS, sent|optional }, /* in MDI client */
     { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
-    { WM_SETFOCUS, sent|defwinproc },
-    { WM_MDIACTIVATE, sent|defwinproc },
+    { WM_SETFOCUS, sent|defwinproc|optional },
+    { WM_MDIACTIVATE, sent|defwinproc|optional },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
     { 0 }
@@ -2787,7 +2911,7 @@ static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wPara
                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                       winpos->hwnd, winpos->hwndInsertAfter,
                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
                 dump_winpos_flags(winpos->flags);
@@ -2838,7 +2962,7 @@ static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam,
                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                       winpos->hwnd, winpos->hwndInsertAfter,
                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
                 dump_winpos_flags(winpos->flags);
@@ -2895,7 +3019,8 @@ static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam,
         message != WM_NCHITTEST &&
         message != WM_GETTEXT &&
         message != WM_GETICON &&
-        message != WM_DEVICECHANGE)
+        message != WM_DEVICECHANGE &&
+        message < 0xc000)
     {
         trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
 
@@ -2907,7 +3032,7 @@ static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam,
                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                       winpos->hwnd, winpos->hwndInsertAfter,
                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
                 dump_winpos_flags(winpos->flags);
@@ -3324,7 +3449,7 @@ static void test_mdi_messages(void)
                                 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
                                 mdi_client, 0, GetModuleHandleA(0), NULL);
     assert(mdi_child2);
-    ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE);
+    ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
     ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
     ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
     ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
@@ -3506,6 +3631,7 @@ static void test_WM_SETREDRAW(HWND hwnd)
 {
     DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
 
+    flush_events();
     flush_sequence();
 
     SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
@@ -3524,6 +3650,7 @@ static void test_WM_SETREDRAW(HWND hwnd)
     /* restore original WS_VISIBLE state */
     SetWindowLongA(hwnd, GWL_STYLE, style);
 
+    flush_events();
     flush_sequence();
 }
 
@@ -3536,6 +3663,9 @@ static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     switch (message)
     {
        /* ignore */
@@ -3552,7 +3682,7 @@ static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam
             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                   winpos->hwnd, winpos->hwndInsertAfter,
                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
             dump_winpos_flags(winpos->flags);
@@ -3682,6 +3812,9 @@ static void test_scroll_messages(HWND hwnd)
     INT min, max;
     BOOL ret;
 
+    flush_events();
+    flush_sequence();
+
     min = 0xdeadbeef;
     max = 0xdeadbeef;
     ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
@@ -4029,7 +4162,31 @@ static const struct message WmInitEndSession_4[] = {
 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
 static const struct message WmInitEndSession_5[] = {
     { 0x003B, sent },
-    { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 1, ENDSESSION_LOGOFF },
+    { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
+    { 0 }
+};
+
+static const struct message WmZOrder[] = {
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
+    { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
+    { HCBT_ACTIVATE, hook },
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
+    { WM_GETTEXT, sent|optional },
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+    { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
+    { WM_NCACTIVATE, sent|wparam|lparam, 1, 0 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
+    { HCBT_SETFOCUS, hook },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
+    { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_GETTEXT, sent|optional },
+    { WM_NCCALCSIZE, sent|optional },
     { 0 }
 };
 
@@ -4046,7 +4203,7 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd)
     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
 
-    ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
+    ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
 
     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
@@ -4057,7 +4214,7 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd)
     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
 
-    ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
+    ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
 
     /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
@@ -4070,9 +4227,9 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd)
     ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
     ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
 
-    ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
+    ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
-    ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
+    ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
     ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
 }
 
@@ -4100,36 +4257,45 @@ static void test_messages(void)
     test_WM_SETREDRAW(hwnd);
 
     SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
+    flush_events();
     ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
     ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
 
     ok(GetActiveWindow() == hwnd, "window should be active\n");
     ok(GetFocus() == hwnd, "window should have input focus\n");
     ShowWindow(hwnd, SW_HIDE);
-    ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE);
+    flush_events();
+    ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
 
     ShowWindow(hwnd, SW_SHOW);
+    flush_events();
     ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
 
     ShowWindow(hwnd, SW_HIDE);
+    flush_events();
     ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
 
     ShowWindow(hwnd, SW_SHOWMAXIMIZED);
+    flush_events();
     ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
 
     ShowWindow(hwnd, SW_RESTORE);
-    /* FIXME: add ok_sequence() here */
+    ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", FALSE);
+    flush_events();
     flush_sequence();
 
     ShowWindow(hwnd, SW_MINIMIZE);
+    flush_events();
     ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
     flush_sequence();
 
     ShowWindow(hwnd, SW_RESTORE);
-    /* FIXME: add ok_sequence() here */
+    flush_events();
+    ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
     flush_sequence();
 
     ShowWindow(hwnd, SW_SHOW);
+    flush_events();
     ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
 
     ok(GetActiveWindow() == hwnd, "window should be active\n");
@@ -4141,6 +4307,7 @@ static void test_messages(void)
 
     /* test WM_SETREDRAW on a visible top level window */
     ShowWindow(hwnd, SW_SHOW);
+    flush_events();
     test_WM_SETREDRAW(hwnd);
 
     trace("testing scroll APIs on a visible top level window %p\n", hwnd);
@@ -4155,7 +4322,7 @@ static void test_messages(void)
     ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
     flush_events();
     flush_sequence();
-    SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER );
+    SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
     ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
     flush_events();
     flush_sequence();
@@ -4283,7 +4450,7 @@ static void test_messages(void)
     ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
     flush_sequence();
     SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
-    ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", TRUE);
+    ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
     DestroyWindow(hchild);
 
     /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
@@ -4460,42 +4627,70 @@ static void test_messages(void)
 
     flush_sequence();
     res = SendMessage(hwnd, 0x3B, 0x8000000b, 0);
+    if (!res)
+    {
+        todo_wine win_skip( "Message 0x3b not supported\n" );
+        goto done;
+    }
     ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
-    todo_wine
     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
     res = SendMessage(hwnd, 0x3B, 0x0000000b, 0);
     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
-    todo_wine
     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
     res = SendMessage(hwnd, 0x3B, 0x0000000f, 0);
     ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
-    todo_wine
     ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
 
     flush_sequence();
     res = SendMessage(hwnd, 0x3B, 0x80000008, 0);
     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
-    todo_wine
     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
     res = SendMessage(hwnd, 0x3B, 0x00000008, 0);
     ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
-    todo_wine
     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
 
     res = SendMessage(hwnd, 0x3B, 0x80000004, 0);
     ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
-    todo_wine
     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
 
     res = SendMessage(hwnd, 0x3B, 0x80000001, 0);
     ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
-    todo_wine
     ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
 
+done:
     DestroyWindow(hwnd);
     flush_sequence();
 }
 
+static void test_setwindowpos(void)
+{
+    HWND hwnd;
+    RECT rc;
+    LRESULT res;
+    const INT winX = 100;
+    const INT winY = 100;
+    const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
+
+    hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
+                           0, 0, winX, winY, 0,
+                           NULL, NULL, 0);
+
+    GetWindowRect(hwnd, &rc);
+    expect(sysX, rc.right);
+    expect(winY, rc.bottom);
+
+    flush_events();
+    flush_sequence();
+    res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
+    ok_sequence(WmZOrder, "Z-Order", TRUE);
+    ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
+
+    GetWindowRect(hwnd, &rc);
+    expect(sysX, rc.right);
+    expect(winY, rc.bottom);
+    DestroyWindow(hwnd);
+}
+
 static void invisible_parent_tests(void)
 {
     HWND hparent, hchild;
@@ -4749,6 +4944,9 @@ static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam,
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
@@ -4859,7 +5057,7 @@ static void test_button_messages(void)
     ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE);
 
     flush_sequence();
-    zfont = (HFONT)GetStockObject(SYSTEM_FONT);
+    zfont = GetStockObject(SYSTEM_FONT);
     SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
     UpdateWindow(hwnd);
     ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE);
@@ -4890,6 +5088,9 @@ static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam,
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
@@ -5076,8 +5277,8 @@ static const struct message WmImeKeydownMsgSeq_0[] =
 
 static const struct message WmImeKeydownMsgSeq_1[] =
 {
-    { WM_KEYDOWN, wparam, VK_RETURN },
-    { WM_CHAR,    wparam, VK_RETURN },
+    { WM_KEYDOWN, optional|wparam, VK_RETURN },
+    { WM_CHAR,    optional|wparam, VK_RETURN },
     { 0 }
 };
 
@@ -5420,7 +5621,9 @@ static void test_paint_messages(void)
     trace("testing ValidateRgn(0, NULL)\n");
     SetLastError(0xdeadbeef);
     ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
-    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError());
+    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
+       broken( GetLastError() == 0xdeadbeef ) /* win9x */,
+       "wrong error code %d\n", GetLastError());
     check_update_rgn( hwnd, 0 );
     flush_events();
     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
@@ -5777,10 +5980,90 @@ static void test_paint_messages(void)
     flush_events();
     ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
 
+    ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
+    ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
+
+    UpdateWindow( hparent );
+    flush_events();
+    flush_sequence();
+    trace("testing SetWindowPos(-10000, -10000) on child\n");
+    SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
+    check_update_rgn( hchild, 0 );
+    flush_events();
+
+#if 0 /* this one doesn't pass under Wine yet */
+    UpdateWindow( hparent );
+    flush_events();
+    flush_sequence();
+    trace("testing ShowWindow(SW_MINIMIZE) on child\n");
+    ShowWindow( hchild, SW_MINIMIZE );
+    check_update_rgn( hchild, 0 );
+    flush_events();
+#endif
+
+    UpdateWindow( hparent );
+    flush_events();
+    flush_sequence();
+    trace("testing SetWindowPos(-10000, -10000) on parent\n");
+    SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
+    check_update_rgn( hparent, 0 );
+    flush_events();
+
     log_all_parent_messages--;
     DestroyWindow( hparent );
     ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
 
+    /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
+
+    hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
+                              100, 100, 200, 200, 0, 0, 0, NULL);
+    ok (hparent != 0, "Failed to create parent window\n");
+
+    hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
+                           10, 10, 100, 100, hparent, 0, 0, NULL);
+    ok (hchild != 0, "Failed to create child window\n");
+
+    ShowWindow( hparent, SW_SHOW );
+    UpdateWindow( hparent );
+    UpdateWindow( hchild );
+    flush_events();
+    flush_sequence();
+
+    /* moving child outside of parent boundaries changes update region */
+    SetRect( &rect, 0, 0, 40, 40 );
+    RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
+    SetRectRgn( hrgn, 0, 0, 40, 40 );
+    check_update_rgn( hchild, hrgn );
+    MoveWindow( hchild, -10, 10, 100, 100, FALSE );
+    SetRectRgn( hrgn, 10, 0, 40, 40 );
+    check_update_rgn( hchild, hrgn );
+    MoveWindow( hchild, -10, -10, 100, 100, FALSE );
+    SetRectRgn( hrgn, 10, 10, 40, 40 );
+    check_update_rgn( hchild, hrgn );
+
+    /* moving parent off-screen does too */
+    SetRect( &rect, 0, 0, 100, 100 );
+    RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
+    SetRectRgn( hrgn, 0, 0, 100, 100 );
+    check_update_rgn( hparent, hrgn );
+    SetRectRgn( hrgn, 10, 10, 40, 40 );
+    check_update_rgn( hchild, hrgn );
+    MoveWindow( hparent, -20, -20, 200, 200, FALSE );
+    SetRectRgn( hrgn, 20, 20, 100, 100 );
+    check_update_rgn( hparent, hrgn );
+    SetRectRgn( hrgn, 30, 30, 40, 40 );
+    check_update_rgn( hchild, hrgn );
+
+    /* invalidated region is cropped by the parent rects */
+    SetRect( &rect, 0, 0, 50, 50 );
+    RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
+    SetRectRgn( hrgn, 30, 30, 50, 50 );
+    check_update_rgn( hchild, hrgn );
+
+    DestroyWindow( hparent );
+    ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
+    flush_sequence();
+
     DeleteObject( hrgn );
     DeleteObject( hrgn2 );
 }
@@ -5860,7 +6143,7 @@ static void test_interthread_messages(void)
     memset(buf, 0, sizeof(buf));
     SetLastError(0xdeadbeef);
     len = DispatchMessageA(&msg);
-    ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
+    ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
        "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError());
 
     /* the following test causes an exception in user.exe under win9x */
@@ -6141,6 +6424,7 @@ static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
         /* ignore some unwanted messages */
         if (msg.message == WM_MOUSEMOVE ||
             msg.message == WM_GETICON ||
+            msg.message == WM_TIMER ||
             msg.message == WM_DEVICECHANGE)
             continue;
 
@@ -6183,6 +6467,7 @@ static void test_accelerators(void)
     hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1));
     assert(hAccel != 0);
 
+    flush_events();
     pump_msg_loop(hwnd, 0);
     flush_sequence();
 
@@ -6366,6 +6651,9 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     switch (message)
     {
        case WM_ENABLE:
@@ -6434,7 +6722,7 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                   winpos->hwnd, winpos->hwndInsertAfter,
                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
             dump_winpos_flags(winpos->flags);
@@ -6465,17 +6753,12 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
 
        GetClientRect(parent, &rc);
        trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
-
-       trace("ptReserved = (%d,%d)\n"
-              "ptMaxSize = (%d,%d)\n"
-              "ptMaxPosition = (%d,%d)\n"
-              "ptMinTrackSize = (%d,%d)\n"
-              "ptMaxTrackSize = (%d,%d)\n",
-             minmax->ptReserved.x, minmax->ptReserved.y,
-             minmax->ptMaxSize.x, minmax->ptMaxSize.y,
-             minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
-             minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
-             minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+        trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
+              minmax->ptReserved.x, minmax->ptReserved.y,
+              minmax->ptMaxSize.x, minmax->ptMaxSize.y,
+              minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
+              minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
+              minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
 
        ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
           minmax->ptMaxSize.x, rc.right);
@@ -6519,11 +6802,19 @@ static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam,
 
     trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
 
-    /* explicitly ignore WM_GETICON message */
-    if (message == WM_GETICON) return 0;
-
-    msg.message = message;
-    msg.flags = sent|wparam|lparam;
+    switch (message)
+    {
+    case WM_GETICON:
+        /* explicitly ignore WM_GETICON message */
+        return 0;
+    case WM_QUERYENDSESSION:
+    case WM_ENDSESSION:
+        lParam &= ~0x01;  /* Vista adds a 0x01 flag */
+        break;
+    }
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
@@ -6555,6 +6846,9 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     logged_lParam=lParam;
     if (log_all_parent_messages ||
         message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
@@ -6588,7 +6882,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam
                 WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
                 trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+                trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                       winpos->hwnd, winpos->hwndInsertAfter,
                       winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
                 dump_winpos_flags(winpos->flags);
@@ -6659,6 +6953,9 @@ static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARA
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     if (test_def_id)
     {
         DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
@@ -6677,7 +6974,7 @@ static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARA
             WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
             trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+            trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
                   winpos->hwnd, winpos->hwndInsertAfter,
                   winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
             dump_winpos_flags(winpos->flags);
@@ -6815,6 +7112,35 @@ static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LP
     return ret;
 }
 
+LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch (msg)
+    {
+        case WM_CREATE: return 0;
+        case WM_PAINT:
+        {
+            MSG msg2;
+            static int i = 0;
+
+            if (i < 256)
+            {
+                i++;
+                if (PeekMessageA(&msg2, 0, 0, 0, 1))
+                {
+                    TranslateMessage(&msg2);
+                    DispatchMessage(&msg2);
+                }
+                i--;
+            }
+            else ok(broken(1), "infinite loop\n");
+            if ( i == 0)
+                paint_loop_done = 1;
+            return DefWindowProcA(hWnd,msg,wParam,lParam);
+        }
+    }
+    return DefWindowProcA(hWnd,msg,wParam,lParam);
+}
+
 static BOOL RegisterWindowClasses(void)
 {
     WNDCLASSA cls;
@@ -6848,6 +7174,10 @@ static BOOL RegisterWindowClasses(void)
     cls.lpszClassName = "SimpleWindowClass";
     if(!RegisterClassA(&cls)) return FALSE;
 
+    cls.lpfnWndProc = PaintLoopProcA;
+    cls.lpszClassName = "PaintLoopWindowClass";
+    if(!RegisterClassA(&cls)) return FALSE;
+
     cls.style = CS_NOCLOSE;
     cls.lpszClassName = "NoCloseWindowClass";
     if(!RegisterClassA(&cls)) return FALSE;
@@ -6875,6 +7205,35 @@ static BOOL RegisterWindowClasses(void)
     return TRUE;
 }
 
+static BOOL is_our_logged_class(HWND hwnd)
+{
+    char buf[256];
+
+    if (GetClassNameA(hwnd, buf, sizeof(buf)))
+    {
+       if (!lstrcmpiA(buf, "TestWindowClass") ||
+           !lstrcmpiA(buf, "ShowWindowClass") ||
+           !lstrcmpiA(buf, "TestParentClass") ||
+           !lstrcmpiA(buf, "TestPopupClass") ||
+           !lstrcmpiA(buf, "SimpleWindowClass") ||
+           !lstrcmpiA(buf, "TestDialogClass") ||
+           !lstrcmpiA(buf, "MDI_frame_class") ||
+           !lstrcmpiA(buf, "MDI_client_class") ||
+           !lstrcmpiA(buf, "MDI_child_class") ||
+           !lstrcmpiA(buf, "my_button_class") ||
+           !lstrcmpiA(buf, "my_edit_class") ||
+           !lstrcmpiA(buf, "static") ||
+           !lstrcmpiA(buf, "ListBox") ||
+           !lstrcmpiA(buf, "ComboBox") ||
+           !lstrcmpiA(buf, "MyDialogClass") ||
+           !lstrcmpiA(buf, "#32770") ||
+           !lstrcmpiA(buf, "#32768"))
+        return TRUE;
+        trace("ignoring window class %s\n", buf);
+    }
+    return FALSE;
+}
+
 static HHOOK hCBT_hook;
 static DWORD cbt_hook_thread_id;
 
@@ -6893,7 +7252,6 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
        "HCBT_SETFOCUS" };
     const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown";
     HWND hwnd;
-    char buf[256];
 
     trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam);
 
@@ -6935,33 +7293,15 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
     /* Log also SetFocus(0) calls */
     hwnd = wParam ? (HWND)wParam : (HWND)lParam;
 
-    if (GetClassNameA(hwnd, buf, sizeof(buf)))
+    if (is_our_logged_class(hwnd))
     {
-       if (!lstrcmpiA(buf, "TestWindowClass") ||
-           !lstrcmpiA(buf, "ShowWindowClass") ||
-           !lstrcmpiA(buf, "TestParentClass") ||
-           !lstrcmpiA(buf, "TestPopupClass") ||
-           !lstrcmpiA(buf, "SimpleWindowClass") ||
-           !lstrcmpiA(buf, "TestDialogClass") ||
-           !lstrcmpiA(buf, "MDI_frame_class") ||
-           !lstrcmpiA(buf, "MDI_client_class") ||
-           !lstrcmpiA(buf, "MDI_child_class") ||
-           !lstrcmpiA(buf, "my_button_class") ||
-           !lstrcmpiA(buf, "my_edit_class") ||
-           !lstrcmpiA(buf, "static") ||
-           !lstrcmpiA(buf, "ListBox") ||
-           !lstrcmpiA(buf, "ComboBox") ||
-           !lstrcmpiA(buf, "MyDialogClass") ||
-           !lstrcmpiA(buf, "#32770"))
-       {
-           struct message msg;
+        struct message msg;
 
-           msg.message = nCode;
-           msg.flags = hook|wparam|lparam;
-           msg.wParam = wParam;
-           msg.lParam = lParam;
-           add_message(&msg);
-       }
+        msg.message = nCode;
+        msg.flags = hook|wparam|lparam;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(&msg);
     }
     return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
 }
@@ -6974,8 +7314,6 @@ static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
                                    DWORD thread_id,
                                    DWORD event_time)
 {
-    char buf[256];
-
     trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n",
           hevent, event, hwnd, object_id, child_id, thread_id, event_time);
 
@@ -6984,33 +7322,15 @@ static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
     /* ignore mouse cursor events */
     if (object_id == OBJID_CURSOR) return;
 
-    if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf)))
+    if (!hwnd || is_our_logged_class(hwnd))
     {
-       if (!hwnd ||
-           !lstrcmpiA(buf, "TestWindowClass") ||
-           !lstrcmpiA(buf, "TestParentClass") ||
-           !lstrcmpiA(buf, "TestPopupClass") ||
-           !lstrcmpiA(buf, "SimpleWindowClass") ||
-           !lstrcmpiA(buf, "TestDialogClass") ||
-           !lstrcmpiA(buf, "MDI_frame_class") ||
-           !lstrcmpiA(buf, "MDI_client_class") ||
-           !lstrcmpiA(buf, "MDI_child_class") ||
-           !lstrcmpiA(buf, "my_button_class") ||
-           !lstrcmpiA(buf, "my_edit_class") ||
-           !lstrcmpiA(buf, "static") ||
-           !lstrcmpiA(buf, "ListBox") ||
-           !lstrcmpiA(buf, "ComboBox") ||
-           !lstrcmpiA(buf, "MyDialogClass") ||
-           !lstrcmpiA(buf, "#32770"))
-       {
-           struct message msg;
+        struct message msg;
 
-           msg.message = event;
-           msg.flags = winevent_hook|wparam|lparam;
-           msg.wParam = object_id;
-           msg.lParam = child_id;
-           add_message(&msg);
-       }
+        msg.message = event;
+        msg.flags = winevent_hook|wparam|lparam;
+        msg.wParam = object_id;
+        msg.lParam = child_id;
+        add_message(&msg);
     }
 }
 
@@ -7034,7 +7354,7 @@ static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam,
 
 static const struct message WmGetTextLengthAfromW[] = {
     { WM_GETTEXTLENGTH, sent },
-    { WM_GETTEXT, sent },
+    { WM_GETTEXT, sent|optional },
     { 0 }
 };
 
@@ -7164,13 +7484,15 @@ static void test_message_conversion(void)
     newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
-                                     NULL, 0, NULL, NULL ),
+                                     NULL, 0, NULL, NULL ) ||
+        broken(lRes == lstrlenW(dummy_window_text) + 37),
         "got bad length %ld\n", lRes );
 
     SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc );  /* restore old wnd proc */
     lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
     ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
-                                     NULL, 0, NULL, NULL ),
+                                     NULL, 0, NULL, NULL ) ||
+        broken(lRes == lstrlenW(dummy_window_text) + 37),
         "got bad length %ld\n", lRes );
 
     ret = DestroyWindow(hwnd);
@@ -8137,8 +8459,11 @@ struct sendmsg_info
 static DWORD CALLBACK send_msg_thread( LPVOID arg )
 {
     struct sendmsg_info *info = arg;
+    SetLastError( 0xdeadbeef );
     info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
-    if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError());
+    if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
+                        broken(GetLastError() == 0),  /* win9x */
+                        "unexpected error %d\n", GetLastError());
     return 0;
 }
 
@@ -8162,6 +8487,7 @@ static void test_SendMessageTimeout(void)
     HANDLE thread;
     struct sendmsg_info info;
     DWORD tid;
+    BOOL is_win9x;
 
     info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
                                100, 100, 200, 200, 0, 0, 0, NULL);
@@ -8185,17 +8511,18 @@ static void test_SendMessageTimeout(void)
     ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
     ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
 
-    /* 0 means infinite timeout */
+    /* 0 means infinite timeout (but not on win9x) */
     info.timeout = 0;
     info.ret = 0xdeadbeef;
     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
     Sleep(100);
     wait_for_thread( thread );
     CloseHandle( thread );
-    ok( info.ret == 1, "SendMessageTimeout failed\n" );
-    ok_sequence( WmUser, "WmUser", FALSE );
+    is_win9x = !info.ret;
+    if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
+    else ok_sequence( WmUser, "WmUser", FALSE );
 
-    /* timeout is treated as signed despite the prototype */
+    /* timeout is treated as signed despite the prototype (but not on win9x) */
     info.timeout = 0x7fffffff;
     info.ret = 0xdeadbeef;
     thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
@@ -8211,8 +8538,16 @@ static void test_SendMessageTimeout(void)
     Sleep(100);
     wait_for_thread( thread );
     CloseHandle( thread );
-    ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
-    ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
+    if (is_win9x)
+    {
+        ok( info.ret == 1, "SendMessageTimeout failed\n" );
+        ok_sequence( WmUser, "WmUser", FALSE );
+    }
+    else
+    {
+        ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
+        ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
+    }
 
     /* now check for timeout during message processing */
     SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
@@ -8348,6 +8683,9 @@ static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, L
     /* explicitly ignore WM_GETICON message */
     if (message == WM_GETICON) return 0;
 
+    /* ignore registered messages */
+    if (message >= 0xc000) return 0;
+
     msg.message = message;
     msg.flags = sent|wparam|lparam;
     if (defwndproc_counter) msg.flags |= defwinproc;
@@ -8483,7 +8821,7 @@ static const struct message WmKeyUpSkippedSeq[] =
     { 0 }
 };
 
-#define EV_START_STOP 0
+#define EV_STOP 0
 #define EV_SENDMSG 1
 #define EV_ACK 2
 
@@ -8498,9 +8836,8 @@ static DWORD CALLBACK send_msg_thread_2(void *param)
     DWORD ret;
     struct peekmsg_info *info = param;
 
-    trace("thread: waiting for start\n");
-    WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE);
     trace("thread: looping\n");
+    SetEvent(info->hevent[EV_ACK]);
 
     while (1)
     {
@@ -8508,13 +8845,14 @@ static DWORD CALLBACK send_msg_thread_2(void *param)
 
         switch (ret)
         {
-        case WAIT_OBJECT_0 + EV_START_STOP:
+        case WAIT_OBJECT_0 + EV_STOP:
             trace("thread: exiting\n");
             return 0;
 
         case WAIT_OBJECT_0 + EV_SENDMSG:
             trace("thread: sending message\n");
-            SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
+            ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0),
+                "SendNotifyMessageA failed error %u\n", GetLastError());
             SetEvent(info->hevent[EV_ACK]);
             break;
 
@@ -8544,15 +8882,12 @@ static void test_PeekMessage(void)
     UpdateWindow(info.hwnd);
     SetFocus(info.hwnd);
 
-    info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL);
+    info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
     info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
     info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
 
     hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
-    Sleep(100);
-
-    trace("signalling to start looping\n");
-    SetEvent(info.hevent[EV_START_STOP]);
+    WaitForSingleObject(info.hevent[EV_ACK], 10000);
 
     flush_events();
     flush_sequence();
@@ -8574,10 +8909,12 @@ static void test_PeekMessage(void)
     /* pass invalid QS_xxxx flags */
     SetLastError(0xdeadbeef);
     qstatus = GetQueueStatus(0xffffffff);
-    ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus);
-    ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
-
-    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == 0 || broken(qstatus)  /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
+    if (!qstatus)
+    {
+        ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
+        qstatus = GetQueueStatus(qs_all_input);
+    }
     ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
        "wrong qstatus %08x\n", qstatus);
 
@@ -8617,9 +8954,19 @@ static void test_PeekMessage(void)
 
     msg.message = 0;
     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
+    if (ret && msg.message == WM_CHAR)
+    {
+        win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
+        goto done;
+    }
     ok(!ret,
        "PeekMessageA should have returned FALSE instead of msg %04x\n",
         msg.message);
+    if (!sequence_cnt)  /* nt4 doesn't fetch anything with PM_QS_* flags */
+    {
+        win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
+        goto done;
+    }
     ok_sequence(WmUser, "WmUser", FALSE);
 
     qstatus = GetQueueStatus(qs_all_input);
@@ -8635,7 +8982,7 @@ static void test_PeekMessage(void)
        "wrong qstatus %08x\n", qstatus);
 
     msg.message = 0;
-    ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
+    ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
     ok(!ret,
        "PeekMessageA should have returned FALSE instead of msg %04x\n",
         msg.message);
@@ -8861,8 +9208,102 @@ todo_wine {
     ok(qstatus == 0,
        "wrong qstatus %08x\n", qstatus);
 
+    /* some GetMessage tests */
+
+    keybd_event('N', 0, 0, 0);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
+
+    PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
+
+    if (qstatus)
+    {
+        ret = GetMessageA( &msg, 0, 0, 0 );
+        ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
+           "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
+           ret, msg.message, msg.wParam);
+        qstatus = GetQueueStatus(qs_all_input);
+        ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
+    }
+
+    if (qstatus)
+    {
+        ret = GetMessageA( &msg, 0, 0, 0 );
+        ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
+           "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
+           ret, msg.message, msg.wParam);
+        qstatus = GetQueueStatus(qs_all_input);
+        ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
+    }
+
+    keybd_event('N', 0, 0, 0);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
+
+    PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
+
+    if (qstatus & (QS_KEY << 16))
+    {
+        ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
+        ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
+           "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
+           ret, msg.message, msg.wParam);
+        qstatus = GetQueueStatus(qs_all_input);
+        ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
+    }
+
+    if (qstatus)
+    {
+        ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
+        ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
+           "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
+           ret, msg.message, msg.wParam);
+        qstatus = GetQueueStatus(qs_all_input);
+        ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
+    }
+
+    keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
+
+    PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
+
+    trace("signalling to send message\n");
+    SetEvent(info.hevent[EV_SENDMSG]);
+    WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
+    qstatus = GetQueueStatus(qs_all_input);
+    ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
+       "wrong qstatus %08x\n", qstatus);
+
+    if (qstatus & (QS_KEY << 16))
+    {
+        ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
+        ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
+           "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
+           ret, msg.message, msg.wParam);
+        ok_sequence(WmUser, "WmUser", FALSE);
+        qstatus = GetQueueStatus(qs_all_input);
+        ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
+    }
+
+    if (qstatus)
+    {
+        ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
+        ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
+           "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
+           ret, msg.message, msg.wParam);
+        qstatus = GetQueueStatus(qs_all_input);
+        ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
+    }
+done:
     trace("signalling to exit\n");
-    SetEvent(info.hevent[EV_START_STOP]);
+    SetEvent(info.hevent[EV_STOP]);
 
     WaitForSingleObject(hthread, INFINITE);
 
@@ -8982,6 +9423,7 @@ static void test_quit_message(void)
     BOOL ret;
 
     /* test using PostQuitMessage */
+    flush_events();
     PostQuitMessage(0xbeef);
 
     ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
@@ -9042,8 +9484,8 @@ static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
     DWORD start_ticks, end_ticks;
 
     start_ticks = GetTickCount();
-    /* add some deviation (5%) to cover not expected delays */
-    start_ticks += timeout / 20;
+    /* add some deviation (50%) to cover not expected delays */
+    start_ticks += timeout / 2;
 
     do
     {
@@ -9123,17 +9565,20 @@ static void test_TrackMouseEvent(void)
     default_hover_time = 0xdeadbeef;
     SetLastError(0xdeadbeef);
     ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
-    ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
+    ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
+       "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
     if (!ret) default_hover_time = 400;
     trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
 
     SetLastError(0xdeadbeef);
     ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
-    ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
+    ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
+       "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
     if (!ret) hover_width = 4;
     SetLastError(0xdeadbeef);
     ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
-    ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
+    ok(ret || broken(GetLastError() == 0xdeadbeef),  /* win9x */
+       "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
     if (!ret) hover_height = 4;
     trace("hover rect is %u x %d\n", hover_width, hover_height);
 
@@ -9149,6 +9594,7 @@ static void test_TrackMouseEvent(void)
                          NULL, NULL, 0);
     assert(hchild);
 
+    SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
     flush_events();
     flush_sequence();
 
@@ -9159,7 +9605,8 @@ static void test_TrackMouseEvent(void)
     SetLastError(0xdeadbeef);
     ret = pTrackMouseEvent(&tme);
     ok(!ret, "TrackMouseEvent should fail\n");
-    ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
+    ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
+       "not expected error %u\n", GetLastError());
 
     tme.cbSize = sizeof(tme);
     tme.dwFlags = TME_HOVER;
@@ -9168,7 +9615,8 @@ static void test_TrackMouseEvent(void)
     SetLastError(0xdeadbeef);
     ret = pTrackMouseEvent(&tme);
     ok(!ret, "TrackMouseEvent should fail\n");
-    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
+    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
+       "not expected error %u\n", GetLastError());
 
     tme.cbSize = sizeof(tme);
     tme.dwFlags = TME_HOVER | TME_CANCEL;
@@ -9177,7 +9625,8 @@ static void test_TrackMouseEvent(void)
     SetLastError(0xdeadbeef);
     ret = pTrackMouseEvent(&tme);
     ok(!ret, "TrackMouseEvent should fail\n");
-    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError());
+    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
+       "not expected error %u\n", GetLastError());
 
     GetWindowRect(hwnd, &rc_parent);
     GetWindowRect(hchild, &rc_child);
@@ -9242,9 +9691,9 @@ static void test_TrackMouseEvent(void)
 static const struct message WmSetWindowRgn[] = {
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
     { WM_NCCALCSIZE, sent|wparam, 1 },
-    { WM_NCPAINT, sent }, /* wparam != 1 */
+    { WM_NCPAINT, sent|optional }, /* wparam != 1 */
     { WM_GETTEXT, sent|defwinproc|optional },
-    { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
+    { WM_ERASEBKGND, sent|optional },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
     { 0 }
@@ -9259,14 +9708,24 @@ static const struct message WmSetWindowRgn_no_redraw[] = {
 };
 
 static const struct message WmSetWindowRgn_clear[] = {
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
     { WM_NCCALCSIZE, sent|wparam, 1 },
-    { WM_NCPAINT, sent }, /* wparam != 1 */
+    { WM_NCPAINT, sent|optional },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
-    { WM_NCPAINT, sent|optional }, /* wparam != 1 */
+    { WM_NCPAINT, sent|optional },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_NCCALCSIZE, sent|optional|wparam, 1 },
+    { WM_NCPAINT, sent|optional },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
+    { WM_NCCALCSIZE, sent|optional|wparam, 1 },
+    { WM_NCPAINT, sent|optional },
     { WM_GETTEXT, sent|defwinproc|optional },
     { WM_ERASEBKGND, sent|optional },
     { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
@@ -9422,7 +9881,7 @@ static const struct message WmHide_3[] = {
     { WM_SHOWWINDOW, sent|wparam, 0 },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
-    { HCBT_SETFOCUS, hook },
+    { HCBT_SETFOCUS, hook|optional },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { 0 }
 };
@@ -9448,6 +9907,7 @@ static const struct message WmMinimize_1[] = {
 };
 static const struct message WmMinimize_2[] = {
     { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
+    { HCBT_SETFOCUS, hook|optional },
     { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
     { WM_MOVE, sent|defwinproc },
@@ -9500,15 +9960,17 @@ static const struct message WmShowMaximized_1[] = {
 static const struct message WmShowMaximized_2[] = {
     { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
     { WM_GETMINMAXINFO, sent },
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
-    { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { HCBT_ACTIVATE, hook|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
     { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
     { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
-    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
+    { WM_WINDOWPOSCHANGING, sent },
+    { HCBT_SETFOCUS, hook|optional },
     { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
     { WM_MOVE, sent|defwinproc },
     { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
-    { HCBT_SETFOCUS, hook },
+    { HCBT_SETFOCUS, hook|optional },
     { 0 }
 };
 static const struct message WmShowMaximized_3[] = {
@@ -9567,7 +10029,7 @@ static void test_ShowWindow(void)
 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE },
 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE },
 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE },
-/* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE },
+/* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE },
 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE },
 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */
 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE },
@@ -9656,7 +10118,7 @@ static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPAR
         WINDOWPOS *winpos = (WINDOWPOS *)lParam;
 
         trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED");
-        trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n",
+        trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x ",
               winpos->hwnd, winpos->hwndInsertAfter,
               winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags);
         dump_winpos_flags(winpos->flags);
@@ -9868,6 +10330,167 @@ static void test_nullCallback(void)
     DestroyWindow(hwnd);
 }
 
+/* SetActiveWindow( 0 ) hwnd visible */
+static const struct message SetActiveWindowSeq0[] =
+{
+    { HCBT_ACTIVATE, hook },
+    { WM_NCACTIVATE, sent|wparam, 0 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 0 },
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { HCBT_SETFOCUS, hook },
+    { WM_KILLFOCUS, sent|defwinproc },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
+    { WM_SETFOCUS, sent|defwinproc },
+    { WM_GETTEXT, sent|optional },
+    { 0 }
+};
+/* SetActiveWindow( hwnd ) hwnd visible */
+static const struct message SetActiveWindowSeq1[] =
+{
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { 0 }
+};
+/* SetActiveWindow( popup ) hwnd visible, popup visible */
+static const struct message SetActiveWindowSeq2[] =
+{
+    { HCBT_ACTIVATE, hook },
+    { WM_NCACTIVATE, sent|wparam, 0 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 0 },
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+    { WM_NCPAINT, sent|optional },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ERASEBKGND, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { HCBT_SETFOCUS, hook },
+    { WM_KILLFOCUS, sent|defwinproc },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
+    { WM_SETFOCUS, sent|defwinproc },
+    { WM_GETTEXT, sent|optional },
+    { 0 }
+};
+
+/* SetActiveWindow( hwnd ) hwnd not visible */
+static const struct message SetActiveWindowSeq3[] =
+{
+    { HCBT_ACTIVATE, hook },
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { HCBT_SETFOCUS, hook },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
+    { WM_SETFOCUS, sent|defwinproc },
+    { 0 }
+};
+/* SetActiveWindow( popup ) hwnd not visible, popup not visible */
+static const struct message SetActiveWindowSeq4[] =
+{
+    { HCBT_ACTIVATE, hook },
+    { WM_NCACTIVATE, sent|wparam, 0 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 0 },
+    { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
+    { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
+    { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_GETTEXT, sent|defwinproc|optional },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { HCBT_SETFOCUS, hook },
+    { WM_KILLFOCUS, sent|defwinproc },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
+    { WM_SETFOCUS, sent|defwinproc },
+    { 0 }
+};
+
+
+static void test_SetActiveWindow(void)
+{
+    HWND hwnd, popup, ret;
+
+    hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
+                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+                           100, 100, 200, 200, 0, 0, 0, NULL);
+
+    popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
+                           WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
+                           100, 100, 200, 200, hwnd, 0, 0, NULL);
+
+    ok(hwnd != 0, "Failed to create overlapped window\n");
+    flush_sequence();
+
+    ok(popup != 0, "Failed to create popup window\n");
+    flush_sequence();
+
+    trace("SetActiveWindow(0)\n");
+    ret = SetActiveWindow(0);
+    ok( ret == popup, "Failed to SetActiveWindow(0)\n");
+    ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", TRUE);
+    flush_sequence();
+
+    trace("SetActiveWindow(hwnd), hwnd visible\n");
+    ret = SetActiveWindow(hwnd);
+    todo_wine
+    {
+        ok( ret == hwnd, "Failed to SetActiveWindow(hwnd), hwnd visible\n");
+    }
+    ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
+    flush_sequence();
+
+    trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
+    ret = SetActiveWindow(popup);
+    ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
+    ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
+    flush_sequence();
+
+    ShowWindow(hwnd, SW_HIDE);
+    ShowWindow(popup, SW_HIDE);
+    flush_sequence();
+
+    trace("SetActiveWindow(hwnd), hwnd not visible\n");
+    ret = SetActiveWindow(hwnd);
+    ok( ret == NULL, "Failed to SetActiveWindow(hwnd), hwnd not visible\n");
+    ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
+    flush_sequence();
+
+    trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
+    ret = SetActiveWindow(popup);
+    ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
+    ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
+    flush_sequence();
+
+    trace("done\n");
+
+    DestroyWindow(hwnd);
+}
+
 static const struct message SetForegroundWindowSeq[] =
 {
     { WM_NCACTIVATE, sent|wparam, 0 },
@@ -10224,7 +10847,7 @@ static const struct message wm_lb_click_0[] =
     { HCBT_SETFOCUS, hook },
     { WM_KILLFOCUS, sent|parent },
     { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
-    { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
     { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
     { WM_SETFOCUS, sent|defwinproc },
 
@@ -10365,6 +10988,315 @@ static void test_listbox_messages(void)
     DestroyWindow(parent);
 }
 
+/*************************** Menu test ******************************/
+static const struct message wm_popup_menu_1[] =
+{
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
+    { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
+    { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
+    { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
+    { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
+    { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
+    { WM_INITMENU, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
+    { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
+    { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
+    { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
+    { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
+    { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
+    { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
+    { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
+    { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
+    { 0 }
+};
+static const struct message wm_popup_menu_2[] =
+{
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
+    { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
+    { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
+    { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
+    { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
+    { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
+    { WM_INITMENU, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
+    { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
+    { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
+    { HCBT_CREATEWND, hook },
+    { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
+                               |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
+    { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
+    { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
+    { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
+    { HCBT_DESTROYWND, hook },
+    { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
+    { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
+    { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
+    { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
+    { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
+    { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
+    { 0 }
+};
+static const struct message wm_popup_menu_3[] =
+{
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
+    { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
+    { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
+    { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
+    { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
+    { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
+    { WM_INITMENU, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
+    { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
+    { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
+    { HCBT_CREATEWND, hook },
+    { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
+                               |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
+    { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
+    { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
+    { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
+    { HCBT_DESTROYWND, hook },
+    { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
+    { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
+    { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
+    { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
+    { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
+    { WM_COMMAND, sent|wparam|lparam, 100, 0 },
+    { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
+    { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
+    { 0 }
+};
+
+static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
+{
+    if (message == WM_ENTERIDLE ||
+        message == WM_INITMENU ||
+        message == WM_INITMENUPOPUP ||
+        message == WM_MENUSELECT ||
+        message == WM_PARENTNOTIFY ||
+        message == WM_ENTERMENULOOP ||
+        message == WM_EXITMENULOOP ||
+        message == WM_UNINITMENUPOPUP ||
+        message == WM_KEYDOWN ||
+        message == WM_KEYUP ||
+        message == WM_CHAR ||
+        message == WM_SYSKEYDOWN ||
+        message == WM_SYSKEYUP ||
+        message == WM_SYSCHAR ||
+        message == WM_COMMAND ||
+        message == WM_MENUCOMMAND)
+    {
+        struct message msg;
+
+        trace("parent_menu_proc: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        msg.wParam = wp;
+        msg.lParam = lp;
+        add_message(&msg);
+    }
+
+    return DefWindowProcA(hwnd, message, wp, lp);
+}
+
+static void set_menu_style(HMENU hmenu, DWORD style)
+{
+    MENUINFO mi;
+    BOOL ret;
+
+    mi.cbSize = sizeof(mi);
+    mi.fMask = MIM_STYLE;
+    mi.dwStyle = style;
+    SetLastError(0xdeadbeef);
+    ret = pSetMenuInfo(hmenu, &mi);
+    ok(ret, "SetMenuInfo error %u\n", GetLastError());
+}
+
+static DWORD get_menu_style(HMENU hmenu)
+{
+    MENUINFO mi;
+    BOOL ret;
+
+    mi.cbSize = sizeof(mi);
+    mi.fMask = MIM_STYLE;
+    mi.dwStyle = 0;
+    SetLastError(0xdeadbeef);
+    ret = pGetMenuInfo(hmenu, &mi);
+    ok(ret, "GetMenuInfo error %u\n", GetLastError());
+
+    return mi.dwStyle;
+}
+
+static void test_menu_messages(void)
+{
+    MSG msg;
+    WNDCLASSA cls;
+    HMENU hmenu, hmenu_popup;
+    HWND hwnd;
+    DWORD style;
+
+    if (!pGetMenuInfo || !pSetMenuInfo)
+    {
+        skip("GetMenuInfo and/or SetMenuInfo are not available\n");
+        return;
+    }
+    cls.style = 0;
+    cls.lpfnWndProc = parent_menu_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(0);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "TestMenuClass";
+    UnregisterClass(cls.lpszClassName, cls.hInstance);
+    if (!RegisterClassA(&cls)) assert(0);
+
+    SetLastError(0xdeadbeef);
+    hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+                           100, 100, 200, 200, 0, 0, 0, NULL);
+    ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1));
+    ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
+
+    SetMenu(hwnd, hmenu);
+    SetForegroundWindow( hwnd );
+
+    set_menu_style(hmenu, MNS_NOTIFYBYPOS);
+    style = get_menu_style(hmenu);
+    ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
+
+    hmenu_popup = GetSubMenu(hmenu, 0);
+    ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
+    style = get_menu_style(hmenu_popup);
+    ok(style == 0, "expected 0, got %u\n", style);
+
+    hmenu_popup = GetSubMenu(hmenu_popup, 0);
+    ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
+    style = get_menu_style(hmenu_popup);
+    ok(style == 0, "expected 0, got %u\n", style);
+
+    /* Alt+E, Enter */
+    trace("testing a popup menu command\n");
+    flush_sequence();
+    keybd_event(VK_MENU, 0, 0, 0);
+    keybd_event('E', 0, 0, 0);
+    keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_RETURN, 0, 0, 0);
+    keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+    ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
+
+    /* Alt+F, Right, Enter */
+    trace("testing submenu of a popup menu command\n");
+    flush_sequence();
+    keybd_event(VK_MENU, 0, 0, 0);
+    keybd_event('F', 0, 0, 0);
+    keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_RIGHT, 0, 0, 0);
+    keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_RETURN, 0, 0, 0);
+    keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+    ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
+
+    set_menu_style(hmenu, 0);
+    style = get_menu_style(hmenu);
+    ok(style == 0, "expected 0, got %u\n", style);
+
+    hmenu_popup = GetSubMenu(hmenu, 0);
+    ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
+    set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
+    style = get_menu_style(hmenu_popup);
+    ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
+
+    hmenu_popup = GetSubMenu(hmenu_popup, 0);
+    ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
+    style = get_menu_style(hmenu_popup);
+    ok(style == 0, "expected 0, got %u\n", style);
+
+    /* Alt+F, Right, Enter */
+    trace("testing submenu of a popup menu command\n");
+    flush_sequence();
+    keybd_event(VK_MENU, 0, 0, 0);
+    keybd_event('F', 0, 0, 0);
+    keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_RIGHT, 0, 0, 0);
+    keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
+    keybd_event(VK_RETURN, 0, 0, 0);
+    keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+    ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
+
+    DestroyWindow(hwnd);
+    DestroyMenu(hmenu);
+}
+
+
+static void test_paintingloop(void)
+{
+    HWND hwnd;
+
+    paint_loop_done = 0;
+    hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
+                               "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
+                                100, 100, 100, 100, 0, 0, 0, NULL );
+    ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
+    ShowWindow(hwnd,SW_NORMAL);
+    SetFocus(hwnd);
+
+    while (!paint_loop_done)
+    {
+        MSG msg;
+        if (PeekMessageA(&msg, 0, 0, 0, 1))
+        {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+    }
+    DestroyWindow(hwnd);
+}
+
 START_TEST(msg)
 {
     BOOL ret;
@@ -10414,6 +11346,7 @@ START_TEST(msg)
     test_PeekMessage2();
     test_scrollwindowex();
     test_messages();
+    test_setwindowpos();
     test_showwindow();
     invisible_parent_tests();
     test_mdi_messages();
@@ -10434,6 +11367,7 @@ START_TEST(msg)
     test_SendMessageTimeout();
     test_edit_messages();
     test_quit_message();
+    test_SetActiveWindow();
 
     if (!pTrackMouseEvent)
         skip("TrackMouseEvent is not available\n");
@@ -10444,8 +11378,13 @@ START_TEST(msg)
     test_sys_menu();
     test_dialog_messages();
     test_nullCallback();
-    test_SetForegroundWindow();
     test_dbcs_wm_char();
+    test_menu_messages();
+    test_paintingloop();
+    /* keep it the last test, under Windows it tends to break the tests
+     * which rely on active/foreground windows being correct.
+     */
+    test_SetForegroundWindow();
 
     UnhookWindowsHookEx(hCBT_hook);
     if (pUnhookWinEvent)
index a8b6c08..b8e0493 100755 (executable)
@@ -40,7 +40,16 @@ static void test_LoadStringW(void)
 
     /* Check that the string which is returned by LoadStringW matches
        the string at the pointer returned by LoadStringW when called with buflen = 0 */
+    SetLastError(0xdeadbeef);
     length1 = LoadStringW(hInst, 2, (WCHAR *) &resourcepointer, 0); /* get pointer to resource. */
+    if (!length1)
+    {
+        if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+            win_skip( "LoadStringW not implemented\n" );
+        else
+            win_skip( "LoadStringW does not return a pointer to the resource\n" );
+        return;
+    }
     length2 = LoadStringW(hInst, 2, returnedstringw, sizeof(returnedstringw) /sizeof(WCHAR)); /* get resource string */
     ok(length2 > 0, "LoadStringW failed to load resource 2, ret %d, err %d\n", length2, GetLastError());
     ok(length1 == length2, "LoadStringW returned different values dependent on buflen. ret1 %d, ret2 %d\n",
@@ -114,7 +123,8 @@ static void test_LoadStringA (void)
         "LoadString failed: ret %d err %d\n", ret, GetLastError());
 
     ret = LoadStringA(hInst, 0, buf, 0);
-    ok( ret == -1, "LoadStringA did not return -1 when called with buflen = 0, got %d, err %d\n",
+    ok( ret == -1 || broken(ret == 0),
+        "LoadStringA did not return -1 when called with buflen = 0, got %d, err %d\n",
         ret, GetLastError());
 }
 
@@ -170,41 +180,43 @@ static void test_accel1(void)
     ok( hAccel != NULL, "create accelerator table\n");
 
     r = CopyAcceleratorTable( hAccel, NULL, 0 );
-    ok( r == n, "two entries in table\n");
+    ok( r == n || broken(r == 2), /* win9x */
+        "two entries in table %u/%u\n", r, n);
 
-    r = CopyAcceleratorTable( hAccel, &ac[0], r );
-    ok( r == n, "still should be two entries in table\n");
+    r = CopyAcceleratorTable( hAccel, &ac[0], n );
+    ok( r == n || broken(r == 2), /* win9x */
+        "still should be two entries in table %u/%u\n", r, n);
 
     n=0;
     ok( ac[n].cmd == 1000, "cmd 0 not preserved\n");
     ok( ac[n].key == 'A', "key 0 not preserved\n");
     ok( ac[n].fVirt == (FVIRTKEY | FNOINVERT), "fVirt 0 not preserved\n");
 
-    n++;
+    if (++n == r) goto done;
     ok( ac[n].cmd == 0xffff, "cmd 1 not preserved\n");
     ok( ac[n].key == 0xffff, "key 1 not preserved\n");
     ok( ac[n].fVirt == 0x007f, "fVirt 1 not changed\n");
 
-    n++;
+    if (++n == r) goto done;
     ok( ac[n].cmd == 0xfff0, "cmd 2 not preserved\n");
     ok( ac[n].key == 0x00ff, "key 2 not preserved\n");
     ok( ac[n].fVirt == 0x0070, "fVirt 2 not changed\n");
 
-    n++;
+    if (++n == r) goto done;
     ok( ac[n].cmd == 0xfff0, "cmd 3 not preserved\n");
     ok( ac[n].key == 0x00ff, "key 3 not preserved\n");
     ok( ac[n].fVirt == 0x0000, "fVirt 3 not changed\n");
 
-    n++;
+    if (++n == r) goto done;
     ok( ac[n].cmd == 0xfff0, "cmd 4 not preserved\n");
     ok( ac[n].key == 0xffff, "key 4 not preserved\n");
     ok( ac[n].fVirt == 0x0001, "fVirt 4 not changed\n");
-
+done:
     r = DestroyAcceleratorTable( hAccel );
     ok( r, "destroy accelerator table\n");
 
     hAccel = CreateAcceleratorTable( &ac[0], 0 );
-    ok( !hAccel, "zero elements should fail\n");
+    ok( !hAccel || broken(hAccel != NULL), /* nt4 */ "zero elements should fail\n");
 
     /* these will on crash win2k
     hAccel = CreateAcceleratorTable( NULL, 1 );
@@ -220,6 +232,7 @@ static void test_accel2(void)
 {
     ACCEL ac[2], out[2];
     HACCEL hac;
+    int res;
 
     ac[0].cmd   = 0;
     ac[0].fVirt = 0;
@@ -236,8 +249,8 @@ static void test_accel2(void)
 
     /* try a zero count */
     hac = CreateAcceleratorTable( &ac[0], 0 );
-    ok( !hac , "fail\n");
-    ok( !DestroyAcceleratorTable( hac ), "destroy failed\n");
+    ok( !hac || broken(hac != NULL), /* nt4 */ "fail\n");
+    if (!hac) ok( !DestroyAcceleratorTable( hac ), "destroy failed\n");
 
     /* creating one accelerator should work */
     hac = CreateAcceleratorTable( &ac[0], 1 );
@@ -248,9 +261,12 @@ static void test_accel2(void)
     /* how about two of the same type? */
     hac = CreateAcceleratorTable( &ac[0], 2);
     ok( hac != NULL , "fail\n");
-    ok( 2 == CopyAcceleratorTable( hac, NULL, 100 ), "copy null failed\n");
-    ok( 2 == CopyAcceleratorTable( hac, NULL, 0 ), "copy null failed\n");
-    ok( 2 == CopyAcceleratorTable( hac, NULL, 1 ), "copy null failed\n");
+    res = CopyAcceleratorTable( hac, NULL, 100 );
+    ok( res == 2 || broken(res == 0), /* win9x */ "copy null failed %d\n", res);
+    res = CopyAcceleratorTable( hac, NULL, 0 );
+    ok( res == 2, "copy null failed %d\n", res);
+    res = CopyAcceleratorTable( hac, NULL, 1 );
+    ok( res == 2 || broken(res == 0), /* win9x */ "copy null failed %d\n", res);
     ok( 1 == CopyAcceleratorTable( hac, out, 1 ), "copy 1 failed\n");
     ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
     ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
@@ -301,14 +317,18 @@ static void test_accel2(void)
     memset( ac, 0xff, sizeof ac );
     hac = CreateAcceleratorTable( &ac[0], 2);
     ok( hac != NULL , "fail\n");
-    ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n");
+    res = CopyAcceleratorTable( hac, out, 2 );
+    ok( res == 2 || broken(res == 1), /* win9x */ "copy 2 failed %d\n", res);
     /* ok( memcmp( ac, out, sizeof ac ), "tables not different\n"); */
     ok( out[0].cmd == ac[0].cmd, "cmd modified\n");
     ok( out[0].fVirt == (ac[0].fVirt&0x7f), "fVirt not modified\n");
     ok( out[0].key == ac[0].key, "key modified\n");
-    ok( out[1].cmd == ac[1].cmd, "cmd modified\n");
-    ok( out[1].fVirt == (ac[1].fVirt&0x7f), "fVirt not modified\n");
-    ok( out[1].key == ac[1].key, "key modified\n");
+    if (res == 2)
+    {
+        ok( out[1].cmd == ac[1].cmd, "cmd modified\n");
+        ok( out[1].fVirt == (ac[1].fVirt&0x7f), "fVirt not modified\n");
+        ok( out[1].key == ac[1].key, "key modified\n");
+    }
     ok( DestroyAcceleratorTable( hac ), "destroy failed\n");
 }
 
@@ -333,9 +353,13 @@ static void test_PrivateExtractIcons(void) {
     cIcons = pPrivateExtractIconsA(szShell32Dll, 0, 16, 16, ahIcon, aIconId, 3, 0);
     ok(cIcons == 3, "Three icons requested got cIcons=%d\n", cIcons);
 
-    cIcons = pPrivateExtractIconsA(szShell32Dll, 0, MAKELONG(32,16), MAKELONG(32,16), 
-                                  ahIcon, aIconId, 3, 0);
-    ok(cIcons == 4, "Three icons requested, four expected, got cIcons=%d\n", cIcons);
+    /* count must be a multiple of two when getting two sizes */
+    cIcons = pPrivateExtractIconsA(szShell32Dll, 0, MAKELONG(16,32), MAKELONG(16,32),
+                                   ahIcon, aIconId, 3, 0);
+    ok(cIcons == 0 /* vista */ || cIcons == 4, "Three icons requested got cIcons=%d\n", cIcons);
+    cIcons = pPrivateExtractIconsA(szShell32Dll, 0, MAKELONG(16,32), MAKELONG(16,32),
+                                   ahIcon, aIconId, 4, 0);
+    ok(cIcons == 4, "Four icons requested got cIcons=%d\n", cIcons);
 }
 
 static void test_LoadImage(void)
index 7da8a6c..79c036c 100755 (executable)
@@ -165,13 +165,16 @@ FONT 8, "MS Shell Dlg"
 {
     POPUP "&File"
     {
-        MENUITEM "&New", 100
+        POPUP "&New..."
+        {
+            MENUITEM "&New file", 100
+        }
         MENUITEM "&Open", 101
         MENUITEM "&Save", 102
         MENUITEM SEPARATOR
         MENUITEM "E&xit", 103
     }
-    POPUP "Edit"
+    POPUP "&Edit"
     {
         MENUITEM "&Undo", 200
         MENUITEM SEPARATOR
index 3bc407a..9547d54 100644 (file)
@@ -127,6 +127,74 @@ static void scrollbar_test3(void)
 
 }
 
+static void scrollbar_test4(void)
+{
+    BOOL ret;
+    SCROLLBARINFO sbi;
+    RECT rect;
+    BOOL (WINAPI *pGetScrollBarInfo)(HWND, LONG, LPSCROLLBARINFO);
+
+    pGetScrollBarInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetScrollBarInfo");
+    if (!pGetScrollBarInfo)
+    {
+        win_skip("GetScrollBarInfo is not available\n");
+        return;
+    }
+
+    /* Test GetScrollBarInfo to make sure it returns rcScrollBar in screen
+     * coordinates. */
+    sbi.cbSize = sizeof(sbi);
+    ret = pGetScrollBarInfo( hScroll, OBJID_CLIENT, &sbi);
+    ok( ret, "The GetScrollBarInfo() call should not fail.\n" );
+    GetWindowRect( hScroll, &rect );
+    ok( ret, "The GetWindowRect() call should not fail.\n" );
+    ok( !(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)),
+        "unexpected rgstate(0x%x)\n", sbi.rgstate[0]);
+    ok( EqualRect(&rect, &sbi.rcScrollBar),
+        "WindowRect(%d, %d, %d, %d) != rcScrollBar(%d, %d, %d, %d)\n",
+        rect.top, rect.left, rect.bottom, rect.right,
+        sbi.rcScrollBar.top, sbi.rcScrollBar.left,
+        sbi.rcScrollBar.bottom, sbi.rcScrollBar.right );
+
+    /* Test windows horizontal and vertical scrollbar to make sure rcScrollBar
+     * is still returned in screen coordinates by moving the window, and
+     * making sure that it shifts the rcScrollBar value. */
+    ShowWindow( hMainWnd, SW_SHOW );
+    sbi.cbSize = sizeof(sbi);
+    ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi);
+    ok( ret, "The GetScrollBarInfo() call should not fail.\n" );
+    GetWindowRect( hMainWnd, &rect );
+    ok( ret, "The GetWindowRect() call should not fail.\n" );
+    MoveWindow( hMainWnd, rect.left+5, rect.top+5,
+                rect.right-rect.left, rect.bottom-rect.top, TRUE );
+    rect = sbi.rcScrollBar;
+    OffsetRect(&rect, 5, 5);
+    ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi);
+    ok( ret, "The GetScrollBarInfo() call should not fail.\n" );
+    ok( EqualRect(&rect, &sbi.rcScrollBar),
+        "PreviousRect(%d, %d, %d, %d) != CurrentRect(%d, %d, %d, %d)\n",
+        rect.top, rect.left, rect.bottom, rect.right,
+        sbi.rcScrollBar.top, sbi.rcScrollBar.left,
+        sbi.rcScrollBar.bottom, sbi.rcScrollBar.right );
+
+    sbi.cbSize = sizeof(sbi);
+    ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi);
+    ok( ret, "The GetScrollBarInfo() call should not fail.\n" );
+    GetWindowRect( hMainWnd, &rect );
+    ok( ret, "The GetWindowRect() call should not fail.\n" );
+    MoveWindow( hMainWnd, rect.left+5, rect.top+5,
+                rect.right-rect.left, rect.bottom-rect.top, TRUE );
+    rect = sbi.rcScrollBar;
+    OffsetRect(&rect, 5, 5);
+    ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi);
+    ok( ret, "The GetScrollBarInfo() call should not fail.\n" );
+    ok( EqualRect(&rect, &sbi.rcScrollBar),
+        "PreviousRect(%d, %d, %d, %d) != CurrentRect(%d, %d, %d, %d)\n",
+        rect.top, rect.left, rect.bottom, rect.right,
+        sbi.rcScrollBar.top, sbi.rcScrollBar.left,
+        sbi.rcScrollBar.bottom, sbi.rcScrollBar.right );
+}
+
 START_TEST ( scroll )
 {
     WNDCLASSA wc;
@@ -143,7 +211,8 @@ START_TEST ( scroll )
     wc.lpfnWndProc = MyWndProc;
     RegisterClassA(&wc);
 
-    hMainWnd = CreateWindowExA( 0, "MyTestWnd", "Scroll", WS_OVERLAPPEDWINDOW,
+    hMainWnd = CreateWindowExA( 0, "MyTestWnd", "Scroll",
+      WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL,
       CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0 );
 
     if ( !ok( hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n" ) )
@@ -154,6 +223,7 @@ START_TEST ( scroll )
     scrollbar_test1();
     scrollbar_test2();
     scrollbar_test3();
+    scrollbar_test4();
 
     DestroyWindow(hScroll);
     DestroyWindow(hMainWnd);
index 7810db4..6a474ff 100644 (file)
 
 static HWND hMainWnd;
 
-#define expect_eq(expr, value, type, fmt) { type val = expr; ok(val == (value), #expr " expected " #fmt " got " #fmt "\n", (value), val); }
+#define expect_eq(expr, value, type, fmt) { type val = expr; ok(val == (value), #expr " expected " fmt " got " fmt "\n", (value), val); }
 #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \
     r.bottom == _bottom && r.right == _right, "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", \
     r.left, r.top, r.right, r.bottom, _left, _top, _right, _bottom);
 
-int g_nReceivedColorStatic = 0;
+static int g_nReceivedColorStatic = 0;
 
 static HWND build_static(DWORD style)
 {
@@ -63,7 +63,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
     return DefWindowProc(hwnd, msg, wparam, lparam);
 }
 
-void test_updates(int style, int flags)
+static void test_updates(int style, int flags)
 {
     RECT r1 = {20, 20, 30, 30};
     HWND hStatic = build_static(style);
@@ -89,6 +89,10 @@ void test_updates(int style, int flags)
 
     if (flags & TODO_COUNT)
         todo_wine { expect_eq(g_nReceivedColorStatic, exp, int, "%d"); }
+    else if (style == SS_ICON || style == SS_BITMAP)
+        ok( g_nReceivedColorStatic == exp ||
+            broken(g_nReceivedColorStatic == 0), /* win9x */
+            "expected %u got %u\n", exp, g_nReceivedColorStatic );
     else
         expect_eq(g_nReceivedColorStatic, exp, int, "%d");
     DestroyWindow(hStatic);
@@ -108,7 +112,7 @@ START_TEST(static)
     wndclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
     wndclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
     wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
-    wndclass.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
+    wndclass.hbrBackground  = GetStockObject(WHITE_BRUSH);
     wndclass.lpszClassName  = szClassName;
     wndclass.lpszMenuName   = NULL;
     RegisterClassEx(&wndclass);
index 8e95ffd..d613565 100755 (executable)
@@ -22,8 +22,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0500 /* For SPI_GETMOUSEHOVERWIDTH and more */
+#define SPI_SETWHEELSCROLLCHARS   109
 
 #include "wine/test.h"
 #include "windef.h"
@@ -129,12 +128,16 @@ static HDC hdc;
 #define SPI_SETPOWEROFFACTIVE_VALNAME           "PowerOffActive"
 #define SPI_SETDRAGFULLWINDOWS_REGKEY           "Control Panel\\Desktop"
 #define SPI_SETDRAGFULLWINDOWS_VALNAME          "DragFullWindows"
+#define SPI_SETSNAPTODEFBUTTON_REGKEY           "Control Panel\\Mouse"
+#define SPI_SETSNAPTODEFBUTTON_VALNAME          "SnapToDefaultButton"
 #define SPI_SETMOUSEHOVERWIDTH_REGKEY           "Control Panel\\Mouse"
 #define SPI_SETMOUSEHOVERWIDTH_VALNAME          "MouseHoverWidth"
 #define SPI_SETMOUSEHOVERHEIGHT_REGKEY          "Control Panel\\Mouse"
 #define SPI_SETMOUSEHOVERHEIGHT_VALNAME         "MouseHoverHeight"
 #define SPI_SETMOUSEHOVERTIME_REGKEY            "Control Panel\\Mouse"
 #define SPI_SETMOUSEHOVERTIME_VALNAME           "MouseHoverTime"
+#define SPI_SETMOUSESCROLLCHARS_REGKEY          "Control Panel\\Desktop"
+#define SPI_SETMOUSESCROLLCHARS_VALNAME         "WheelScrollChars"
 #define SPI_SETMOUSESCROLLLINES_REGKEY          "Control Panel\\Desktop"
 #define SPI_SETMOUSESCROLLLINES_VALNAME         "WheelScrollLines"
 #define SPI_SETMENUSHOWDELAY_REGKEY             "Control Panel\\Desktop"
@@ -219,7 +222,7 @@ static BOOL test_error_msg ( int rc, const char *name )
 
     if (rc==0)
     {
-        if (last_error==0xdeadbeef || last_error==ERROR_INVALID_SPI_VALUE)
+        if (last_error==0xdeadbeef || last_error==ERROR_INVALID_SPI_VALUE || last_error==ERROR_INVALID_PARAMETER)
         {
             trace("%s not supported on this platform. Skipping test\n", name);
         }
@@ -1773,7 +1776,7 @@ static void test_SPI_SETSHOWSOUNDS( void )             /*     57 */
         rc=SystemParametersInfoA( SPI_SETSHOWSOUNDS, vals[i], 0,
                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        test_change_message( SPI_SETSHOWSOUNDS, 0 );
+        test_change_message( SPI_SETSHOWSOUNDS, 1 );
         test_reg_key( SPI_SETSHOWSOUNDS_REGKEY,
                       SPI_SETSHOWSOUNDS_VALNAME,
                       vals[i] ? "1" : "0" );
@@ -1809,7 +1812,7 @@ static void test_SPI_SETKEYBOARDPREF( void )           /*     69 */
         rc=SystemParametersInfoA( SPI_SETKEYBOARDPREF, vals[i], 0,
                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        test_change_message( SPI_SETKEYBOARDPREF, 0 );
+        test_change_message( SPI_SETKEYBOARDPREF, 1 );
         test_reg_key_ex2( SPI_SETKEYBOARDPREF_REGKEY, SPI_SETKEYBOARDPREF_REGKEY_LEGACY,
                           SPI_SETKEYBOARDPREF_VALNAME, SPI_SETKEYBOARDPREF_VALNAME_LEGACY,
                           vals[i] ? "1" : "0" );
@@ -1843,7 +1846,7 @@ static void test_SPI_SETSCREENREADER( void )           /*     71 */
         rc=SystemParametersInfoA( SPI_SETSCREENREADER, vals[i], 0,
                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        test_change_message( SPI_SETSCREENREADER, 0 );
+        test_change_message( SPI_SETSCREENREADER, 1 );
         test_reg_key_ex2( SPI_SETSCREENREADER_REGKEY, SPI_SETSCREENREADER_REGKEY_LEGACY,
                       SPI_SETSCREENREADER_VALNAME, SPI_SETSCREENREADER_VALNAME_LEGACY,
                       vals[i] ? "1" : "0" );
@@ -1912,14 +1915,17 @@ static void test_SPI_SETLOWPOWERACTIVE( void )         /*     85 */
         rc=SystemParametersInfoA( SPI_SETLOWPOWERACTIVE, vals[i], 0,
                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        test_change_message( SPI_SETLOWPOWERACTIVE, 0 );
+        test_change_message( SPI_SETLOWPOWERACTIVE, 1 );
         test_reg_key( SPI_SETLOWPOWERACTIVE_REGKEY,
                       SPI_SETLOWPOWERACTIVE_VALNAME,
                       vals[i] ? "1" : "0" );
 
+        /* SPI_SETLOWPOWERACTIVE is not persistent in win2k3 and above */
         rc=SystemParametersInfoA( SPI_GETLOWPOWERACTIVE, 0, &v, 0 );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        eq( v, vals[i], "SPI_GETLOWPOWERACTIVE", "%d" );
+        ok(v == vals[i] ||
+           v == 0, /* win2k3 */
+           "SPI_GETLOWPOWERACTIVE: got %d instead of 0 or %d\n", v, vals[i]);
     }
 
     rc=SystemParametersInfoA( SPI_SETLOWPOWERACTIVE, old_b, 0, SPIF_UPDATEINIFILE );
@@ -1946,20 +1952,57 @@ static void test_SPI_SETPOWEROFFACTIVE( void )         /*     86 */
         rc=SystemParametersInfoA( SPI_SETPOWEROFFACTIVE, vals[i], 0,
                                   SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        test_change_message( SPI_SETPOWEROFFACTIVE, 0 );
+        test_change_message( SPI_SETPOWEROFFACTIVE, 1 );
         test_reg_key( SPI_SETPOWEROFFACTIVE_REGKEY,
                       SPI_SETPOWEROFFACTIVE_VALNAME,
                       vals[i] ? "1" : "0" );
 
+        /* SPI_SETPOWEROFFACTIVE is not persistent in win2k3 and above */
         rc=SystemParametersInfoA( SPI_GETPOWEROFFACTIVE, 0, &v, 0 );
         ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
-        eq( v, vals[i], "SPI_GETPOWEROFFACTIVE", "%d" );
+        ok(v == vals[i] ||
+           v == 0, /* win2k3 */
+           "SPI_GETPOWEROFFACTIVE: got %d instead of 0 or %d\n", v, vals[i]);
     }
 
     rc=SystemParametersInfoA( SPI_SETPOWEROFFACTIVE, old_b, 0, SPIF_UPDATEINIFILE );
     ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError());
 }
 
+static void test_SPI_SETSNAPTODEFBUTTON( void )         /*     95 */
+{
+    BOOL rc;
+    BOOL old_b;
+    const UINT vals[]={TRUE,FALSE};
+    unsigned int i;
+
+    trace("testing SPI_{GET,SET}SNAPTODEFBUTTON\n");
+    SetLastError(0xdeadbeef);
+    rc=SystemParametersInfoA( SPI_GETSNAPTODEFBUTTON, 0, &old_b, 0 );
+    if (!test_error_msg(rc,"SPI_GETSNAPTODEFBUTTON"))
+        return;
+
+    for (i=0;i<sizeof(vals)/sizeof(*vals);i++)
+    {
+        UINT v;
+
+        rc=SystemParametersInfoA( SPI_SETSNAPTODEFBUTTON, vals[i], 0,
+                                  SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
+        ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
+        test_change_message( SPI_SETSNAPTODEFBUTTON, 0 );
+        test_reg_key( SPI_SETSNAPTODEFBUTTON_REGKEY,
+                      SPI_SETSNAPTODEFBUTTON_VALNAME,
+                      vals[i] ? "1" : "0" );
+
+        rc=SystemParametersInfoA( SPI_GETSNAPTODEFBUTTON, 0, &v, 0 );
+        ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
+        eq( v, vals[i], "SPI_GETSNAPTODEFBUTTON", "%d" );
+    }
+
+    rc=SystemParametersInfoA( SPI_SETSNAPTODEFBUTTON, old_b, 0, SPIF_UPDATEINIFILE );
+    ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError());
+}
+
 static void test_SPI_SETMOUSEHOVERWIDTH( void )      /*     99 */
 {
     BOOL rc;
@@ -2157,6 +2200,44 @@ static void test_SPI_SETMENUSHOWDELAY( void )      /*     107 */
     ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError());
 }
 
+static void test_SPI_SETWHEELSCROLLCHARS( void )      /*     108 */
+{
+    BOOL rc;
+    UINT old_chars;
+    const UINT vals[]={32767,0};
+    unsigned int i;
+
+    trace("testing SPI_{GET,SET}WHEELSCROLLCHARS\n");
+    SetLastError(0xdeadbeef);
+    rc=SystemParametersInfoA( SPI_GETWHEELSCROLLCHARS, 0, &old_chars, 0 );
+
+    /* SPI_{GET,SET}WHEELSCROLLCHARS not supported on Windows 95 */
+    if (!test_error_msg(rc,"SPI_{GET,SET}WHEELSCROLLCHARS"))
+        return;
+
+    for (i=0;i<sizeof(vals)/sizeof(*vals);i++)
+    {
+        UINT v;
+        char buf[10];
+
+        rc=SystemParametersInfoA( SPI_SETWHEELSCROLLCHARS, vals[i], 0,
+                               SPIF_UPDATEINIFILE | SPIF_SENDCHANGE );
+        if (!test_error_msg(rc,"SPI_SETWHEELSCROLLCHARS")) return;
+        test_change_message( SPI_SETWHEELSCROLLCHARS, 0 );
+        sprintf( buf, "%d", vals[i] );
+        test_reg_key( SPI_SETMOUSESCROLLCHARS_REGKEY,
+                      SPI_SETMOUSESCROLLCHARS_VALNAME, buf );
+
+        SystemParametersInfoA( SPI_GETWHEELSCROLLCHARS, 0, &v, 0 );
+        ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError());
+        eq( v, vals[i], "SPI_{GET,SET}WHEELSCROLLCHARS", "%d" );
+    }
+
+    rc=SystemParametersInfoA( SPI_SETWHEELSCROLLCHARS, old_chars, 0,
+                              SPIF_UPDATEINIFILE );
+    ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError());
+}
+
 static void test_SPI_SETWALLPAPER( void )              /*   115 */
 {
     BOOL rc;
@@ -2294,11 +2375,13 @@ static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam )
     test_SPI_SETFONTSMOOTHING();                /*     75 */
     test_SPI_SETLOWPOWERACTIVE();               /*     85 */
     test_SPI_SETPOWEROFFACTIVE();               /*     86 */
+    test_SPI_SETSNAPTODEFBUTTON();              /*     95 */
     test_SPI_SETMOUSEHOVERWIDTH();              /*     99 */
     test_SPI_SETMOUSEHOVERHEIGHT();             /*    101 */
     test_SPI_SETMOUSEHOVERTIME();               /*    103 */
     test_SPI_SETWHEELSCROLLLINES();             /*    105 */
     test_SPI_SETMENUSHOWDELAY();                /*    107 */
+    test_SPI_SETWHEELSCROLLCHARS();             /*    108 */
     test_SPI_SETWALLPAPER();                    /*    115 */
 
     test_WM_DISPLAYCHANGE();
@@ -2389,6 +2472,8 @@ static void test_GetSystemMetrics( void)
     INT CaptionWidth;
     MINIMIZEDMETRICS minim;
     NONCLIENTMETRICS ncm;
+    SIZE screen;
+
     minim.cbSize = sizeof( minim);
     ncm.cbSize = sizeof( ncm);
     SystemParametersInfo( SPI_GETMINIMIZEDMETRICS, 0, &minim, 0);
@@ -2464,8 +2549,9 @@ static void test_GetSystemMetrics( void)
     /* SM_SECURE */
     ok_gsm( SM_CXEDGE, 2);
     ok_gsm( SM_CYEDGE, 2);
-    ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + minim.iHorzGap );
-    ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + minim.iVertGap );
+    /* sign-extension for iHorzGap/iVertGap is broken on Win9x */
+    ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + (short)minim.iHorzGap );
+    ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + (short)minim.iVertGap );
     /* SM_CXSMICON */
     /* SM_CYSMICON */
     ok_gsm( SM_CYSMCAPTION, ncm.iSmCaptionHeight + 1);
@@ -2481,10 +2567,15 @@ static void test_GetSystemMetrics( void)
     /* SM_ARRANGE */
     ok_gsm( SM_CXMINIMIZED, minim.iWidth + 6);
     ok_gsm( SM_CYMINIMIZED, GetSystemMetrics( SM_CYCAPTION) + 5);
-    ok_gsm( SM_CXMAXTRACK, GetSystemMetrics( SM_CXVIRTUALSCREEN) +
-            4 + 2 * GetSystemMetrics( SM_CXFRAME));
-    ok_gsm( SM_CYMAXTRACK, GetSystemMetrics( SM_CYVIRTUALSCREEN) +
-            4 + 2 * GetSystemMetrics( SM_CYFRAME));
+    screen.cx = GetSystemMetrics( SM_CXVIRTUALSCREEN );
+    screen.cy = GetSystemMetrics( SM_CYVIRTUALSCREEN );
+    if (!screen.cx || !screen.cy)  /* not supported on NT4 */
+    {
+        screen.cx = GetSystemMetrics( SM_CXSCREEN );
+        screen.cy = GetSystemMetrics( SM_CYSCREEN );
+    }
+    ok_gsm( SM_CXMAXTRACK, screen.cx + 4 + 2 * GetSystemMetrics(SM_CXFRAME));
+    ok_gsm( SM_CYMAXTRACK, screen.cy + 4 + 2 * GetSystemMetrics(SM_CYFRAME));
     /* the next two cannot really be tested as they depend on (application)
      * toolbars */
     /* SM_CXMAXIMIZED */
index 1e09650..fc554ae 100755 (executable)
@@ -27,6 +27,9 @@
 #include "winuser.h"
 #include "winerror.h"
 
+#define MODIFIED(rect) (rect.left = 10 && rect.right != 100 && rect.top == 10 && rect.bottom != 100)
+#define SAME(rect) (rect.left = 10 && rect.right == 100 && rect.top == 10 && rect.bottom == 100)
+#define EMPTY(rect) (rect.left == rect.right && rect.bottom == rect.top)
 
 static void test_DrawTextCalcRect(void)
 {
@@ -40,9 +43,11 @@ static void test_DrawTextCalcRect(void)
         's','t','r','i','n','g','\0'};
     static CHAR emptystring[] = "";
     static WCHAR emptystringW[] = { 0 };
-    INT textlen, textheight;
+    INT textlen, textheight, heightcheck;
     RECT rect = { 0, 0, 100, 0 };
     BOOL ret;
+    DRAWTEXTPARAMS dtp;
+    BOOL conform_xp = TRUE;
 
     /* Initialization */
     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
@@ -105,64 +110,441 @@ static void test_DrawTextCalcRect(void)
        rect.bottom);
 
     /* empty or null text should in some cases calc an empty rectangle */
-    /* note: testing the function's return value is useless, it differs
-     * ( 0 or 1) on every Windows version I tried */
+
+    SetRect( &rect, 10,10, 100, 100);
+    heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT, NULL );
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    if (textheight != 0)  /* Windows 98 */
+    {
+        win_skip("XP conformity failed, skipping XP tests. Probably win9x\n");
+        conform_xp = FALSE;
+    }
+    else
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT);
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    SetLastError( 0);
+    heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT, NULL );
+    ok( EMPTY(rect),
+        "rectangle should be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT);
+    ok( EMPTY(rect),
+        "rectangle should be empty got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    SetLastError( 0);
+    heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
+    ok( EMPTY(rect) || !MODIFIED(rect),
+        "rectangle should be empty or not modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    if (!textheight) /* Windows NT 4 */
+    {
+        if (conform_xp)
+            win_skip("XP conformity failed, skipping XP tests. Probably winNT\n");
+        conform_xp = FALSE;
+    }
+    else
+        ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT);
+    ok( EMPTY(rect) || !MODIFIED(rect),
+        "rectangle should be empty or NOT modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT);
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+    /* DT_SINGLELINE tests */
+
+    SetRect( &rect, 10,10, 100, 100);
+    heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+
     SetRect( &rect, 10,10, 100, 100);
-    textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT, NULL );
-    ok( !(rect.left == rect.right && rect.bottom == rect.top),
-            "rectangle should NOT be empty.\n");
+    textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
     SetRect( &rect, 10,10, 100, 100);
     SetLastError( 0);
-    textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT, NULL );
-    ok( (rect.left == rect.right && rect.bottom == rect.top),
-            "rectangle should be empty.\n");
+    heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+    ok( !EMPTY(rect) && MODIFIED(rect),
+        "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
+    ok( !EMPTY(rect) && MODIFIED (rect),
+        "rectangle should be modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
     SetRect( &rect, 10,10, 100, 100);
     SetLastError( 0);
-    textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
-    ok( (rect.left == rect.right && rect.bottom == rect.top),
-            "rectangle should be empty.\n");
+    heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+    ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect),
+        "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
+    ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect),
+        "rectangle should be modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+    SetRect( &rect, 10,10, 100, 100);
+    heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+
     SetRect( &rect, 10,10, 100, 100);
-    textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
-    ok( !(rect.left == rect.right && rect.bottom == rect.top),
-            "rectangle should NOT be empty.\n");
+    textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
+    ok( !EMPTY(rect) && !MODIFIED(rect),
+        "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+        rect.left, rect.top, rect.right, rect.bottom );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+    /* further tests with  0 count, NULL and empty strings */
+    heightcheck = textheight = DrawTextA(hdc, text, 0, &rect, 0);
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    textheight = DrawTextExA(hdc, text, 0, &rect, 0, NULL );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+    heightcheck = textheight = DrawTextA(hdc, emptystring, 0, &rect, 0);
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, NULL );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+    heightcheck = textheight = DrawTextA(hdc, NULL, 0, &rect, 0);
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextA\n");
+    textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, NULL );
+    if (conform_xp)
+        ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+    heightcheck = textheight = DrawTextA(hdc, emptystring, -1, &rect, 0);
+    ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
+    textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, NULL );
+    ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+    heightcheck = textheight = DrawTextA(hdc, NULL, -1, &rect, 0);
+    if (conform_xp)
+        ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
+    textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, NULL );
+    if (conform_xp)
+        ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+    heightcheck = textheight = DrawTextA(hdc, NULL, 10, &rect, 0);
+    ok(textheight==0,"Got textheight from DrawTextA\n");
+    textheight = DrawTextExA(hdc, NULL, 10, &rect, 0, NULL );
+    ok(textheight==0,"Got textheight from DrawTextA\n");
+    ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+
+    /* invalid dtp size test */
+    dtp.cbSize = -1; /* Invalid */
+    dtp.uiLengthDrawn = 1337;
+    textheight = DrawTextExA(hdc, text, 0, &rect, 0, &dtp);
+    ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+    dtp.uiLengthDrawn = 1337;
+    textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, &dtp);
+    ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+    dtp.uiLengthDrawn = 1337;
+    textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, &dtp);
+    ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+    dtp.uiLengthDrawn = 1337;
+    textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, &dtp);
+    ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+    dtp.uiLengthDrawn = 1337;
+    textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, &dtp);
+    ok(textheight==0,"Got textheight from DrawTextExA\n");
+    ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
 
     /* Wide char versions */
     SetRect( &rect, 10,10, 100, 100);
     SetLastError( 0);
-    textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT, NULL );
+    heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT, NULL );
     if( GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) {
-        ok( !(rect.left == rect.right && rect.bottom == rect.top),
-                "rectangle should NOT be empty.\n");
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT);
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT, NULL );
+        ok( EMPTY(rect),
+            "rectangle should be empty got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT);
+        ok( EMPTY(rect),
+            "rectangle should be empty got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        if (textheight) /* windows 2000 */
+        {
+            if (conform_xp)
+                win_skip("XP conformity failed, skipping XP tests. Probably win 2000\n");
+            conform_xp = FALSE;
+        }
+        else
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT);
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+        if (conform_xp) {
+            /* Crashes on NT4 */
+            SetRect( &rect, 10,10, 100, 100);
+            heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
+            ok( !EMPTY(rect) && !MODIFIED(rect),
+                "rectangle should NOT be empty  and NOT modified got %d,%d-%d,%d\n",
+                rect.left, rect.top, rect.right, rect.bottom );
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+
+            SetRect( &rect, 10,10, 100, 100);
+            textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT);
+            ok( !EMPTY(rect) && !MODIFIED(rect),
+                "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+                rect.left, rect.top, rect.right, rect.bottom );
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+            ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        }
+
+
+        /* DT_SINGLELINE tests */
+
+        heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+        SetRect( &rect, 10,10, 100, 100);
+        heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+        ok( !EMPTY(rect) && MODIFIED(rect),
+            "rectangle should be modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+
         SetRect( &rect, 10,10, 100, 100);
-        textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT, NULL );
-        ok( (rect.left == rect.right && rect.bottom == rect.top),
-                "rectangle should be empty.\n");
+        textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
+        ok( !EMPTY(rect) && MODIFIED(rect),
+            "rectangle should be modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+        if (conform_xp) {
+            /* Crashes on NT4 */
+            SetRect( &rect, 10,10, 100, 100);
+            heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+            ok( !EMPTY(rect) && !MODIFIED(rect),
+                "rectangle should NOT be empty  and NOT modified got %d,%d-%d,%d\n",
+                rect.left, rect.top, rect.right, rect.bottom );
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+
+            SetRect( &rect, 10,10, 100, 100);
+            textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
+            ok( !EMPTY(rect) && !MODIFIED(rect),
+                "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+                rect.left, rect.top, rect.right, rect.bottom );
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+            ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        }
+
         SetRect( &rect, 10,10, 100, 100);
-        textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
-        ok( !(rect.left == rect.right && rect.bottom == rect.top),
-                "rectangle should NOT be empty.\n");
+        heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+
         SetRect( &rect, 10,10, 100, 100);
-        textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
-        ok( !(rect.left == rect.right && rect.bottom == rect.top),
-                "rectangle should NOT be empty.\n");
+        textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
+        ok( !EMPTY(rect) && !MODIFIED(rect),
+            "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
+            rect.left, rect.top, rect.right, rect.bottom );
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+
+        /* further tests with NULL and empty strings */
+        heightcheck = textheight = DrawTextW(hdc, textW, 0, &rect, 0);
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        textheight = DrawTextExW(hdc, textW, 0, &rect, 0, NULL );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        heightcheck = textheight = DrawTextW(hdc, emptystringW, 0, &rect, 0);
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, NULL );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        heightcheck = textheight = DrawTextW(hdc, NULL, 0, &rect, 0);
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+        textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, NULL );
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        heightcheck = textheight = DrawTextW(hdc, emptystringW, -1, &rect, 0);
+        ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
+        textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, NULL );
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+        ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        if (conform_xp) {
+            /* Crashes on NT4 */
+            heightcheck = textheight = DrawTextW(hdc, NULL, -1, &rect, 0);
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+            textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, NULL );
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+            ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+            heightcheck = textheight = DrawTextW(hdc, NULL, 10, &rect, 0);
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+            textheight = DrawTextExW(hdc, NULL, 10, &rect, 0, NULL );
+            ok(textheight==0,"Got textheight from DrawTextW\n");
+            ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
+        }
+
+        dtp.cbSize = -1; /* Invalid */
+        dtp.uiLengthDrawn = 1337;
+        textheight = DrawTextExW(hdc, textW, 0, &rect, 0, &dtp);
+        ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
+        ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+        dtp.uiLengthDrawn = 1337;
+        textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, &dtp);
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+        ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+        dtp.uiLengthDrawn = 1337;
+        textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, &dtp);
+        if (conform_xp)
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+        ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+        dtp.uiLengthDrawn = 1337;
+        textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, &dtp);
+        ok(textheight==0,"Got textheight from DrawTextExW\n");
+        ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+        if (conform_xp) {
+            /* Crashes on NT4 */
+            dtp.uiLengthDrawn = 1337;
+            textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, &dtp);
+            ok(textheight==0,"Got textheight from DrawTextExW\n");
+            ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
+        }
     }
 
     /* More test cases from bug 12226 */
     SetRect(&rect, 0, 0, 0, 0);
     textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE);
-    todo_wine ok(textheight, "DrawTextA error %u\n", GetLastError());
+    ok(textheight, "DrawTextA error %u\n", GetLastError());
     ok(0 == rect.left, "expected 0, got %d\n", rect.left);
     ok(0 == rect.right, "expected 0, got %d\n", rect.right);
     ok(0 == rect.top, "expected 0, got %d\n", rect.top);
-    todo_wine ok(rect.bottom, "rect.bottom should not be 0\n");
+    ok(rect.bottom, "rect.bottom should not be 0\n");
 
     SetRect(&rect, 0, 0, 0, 0);
     textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE);
-    todo_wine ok(textheight, "DrawTextW error %u\n", GetLastError());
-    ok(0 == rect.left, "expected 0, got %d\n", rect.left);
-    ok(0 == rect.right, "expected 0, got %d\n", rect.right);
-    ok(0 == rect.top, "expected 0, got %d\n", rect.top);
-    todo_wine ok(rect.bottom, "rect.bottom should not be 0\n");
+    if (!textheight && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip( "DrawTextW not implemented\n" );
+    }
+    else
+    {
+        ok(textheight, "DrawTextW error %u\n", GetLastError());
+        ok(0 == rect.left, "expected 0, got %d\n", rect.left);
+        ok(0 == rect.right, "expected 0, got %d\n", rect.right);
+        ok(0 == rect.top, "expected 0, got %d\n", rect.top);
+        ok(rect.bottom, "rect.bottom should not be 0\n");
+    }
 
     SelectObject(hdc, hOldFont);
     ret = DeleteObject(hFont);
@@ -292,13 +674,13 @@ static void test_DrawState(void)
     SetLastError(0xdeadbeef);
     ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, strlen(text),
                     0, 0, 10, 10, DST_TEXT);
-    ok(!ret, "DrawState succeeded\n");
+    ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n");
     ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, 0,
                     0, 0, 10, 10, DST_TEXT);
-    ok(!ret, "DrawState succeeded\n");
+    ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n");
     ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
 
     ReleaseDC(hwnd, hdc);
index 5b391eb..96a594b 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 /* To get ICON_SMALL2 with the MSVC headers */
-#define _WIN32_WINNT 0x0501
 
 #include <assert.h>
 #include <stdlib.h>
@@ -46,6 +45,11 @@ void dump_region(HRGN hrgn);
 
 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
 static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*);
+static UINT (WINAPI *pGetWindowModuleFileNameA)(HWND,LPSTR,UINT);
+static BOOL (WINAPI *pGetLayeredWindowAttributes)(HWND,COLORREF*,BYTE*,DWORD*);
+static BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD);
+static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
+static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
 
 static BOOL test_lbuttondown_flag;
 static HWND hwndMessage;
@@ -58,6 +62,16 @@ static DWORD our_pid;
 
 #define COUNTOF(arr) (sizeof(arr)/sizeof(arr[0]))
 
+static void dump_minmax_info( const MINMAXINFO *minmax )
+{
+    trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
+          minmax->ptReserved.x, minmax->ptReserved.y,
+          minmax->ptMaxSize.x, minmax->ptMaxSize.y,
+          minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
+          minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
+          minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+}
+
 /* try to make sure pending X events have been processed before continuing */
 static void flush_events( BOOL remove_messages )
 {
@@ -141,8 +155,10 @@ static void test_parent_owner(void)
     SetLastError(0xdeadbeef);
     test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1",
                            WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL );
-    ok( GetLastError() == ERROR_TLW_WITH_WSCHILD, "CreateWindowExA should call SetLastError\n" );
     ok( !test, "WS_CHILD without parent created\n" );
+    ok( GetLastError() == ERROR_TLW_WITH_WSCHILD ||
+        broken(GetLastError() == 0xdeadbeef), /* win9x */
+        "CreateWindowExA error %u\n", GetLastError() );
 
     /* desktop window */
     check_parents( desktop, 0, 0, 0, 0, 0, 0 );
@@ -551,13 +567,7 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR
            MINMAXINFO* minmax = (MINMAXINFO *)lparam;
 
            trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam);
-            trace("ptReserved (%d,%d), ptMaxSize (%d,%d), ptMaxPosition (%d,%d)\n"
-                  "      ptMinTrackSize (%d,%d), ptMaxTrackSize (%d,%d)\n",
-                 minmax->ptReserved.x, minmax->ptReserved.y,
-                 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
-                 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
-                 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
-                 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+            dump_minmax_info( minmax );
            SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0x20031021);
            break;
        }
@@ -651,13 +661,7 @@ static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR
            MINMAXINFO* minmax = (MINMAXINFO *)lparam;
 
            trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam);
-            trace("ptReserved (%d,%d), ptMaxSize (%d,%d), ptMaxPosition (%d,%d)\n"
-                  "      ptMinTrackSize (%d,%d), ptMaxTrackSize (%d,%d)\n",
-                 minmax->ptReserved.x, minmax->ptReserved.y,
-                 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
-                 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
-                 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
-                 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+            dump_minmax_info( minmax );
            SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0x20031021);
            break;
        }
@@ -731,17 +735,15 @@ static void verify_window_info(HWND hwnd, const WINDOWINFO *info)
 
     ok(info->dwStyle == (DWORD)GetWindowLongA(hwnd, GWL_STYLE),
        "wrong dwStyle: %08x != %08x\n", info->dwStyle, GetWindowLongA(hwnd, GWL_STYLE));
-    /* Windows reports a not documented exstyle 0x800 in WINDOWINFO, but
-     * doesn't return it in GetWindowLong(hwnd, GWL_EXSTYLE).
+    /* Windows reports some undocumented exstyles in WINDOWINFO, but
+     * doesn't return them in GetWindowLong(hwnd, GWL_EXSTYLE).
      */
-    ok((info->dwExStyle & ~0x800) == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE),
+    ok((info->dwExStyle & ~0xe0000800) == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE),
        "wrong dwExStyle: %08x != %08x\n", info->dwExStyle, GetWindowLongA(hwnd, GWL_EXSTYLE));
     status = (GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0;
-    ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04x != %04x\n",
-       info->dwWindowStatus, status);
-
-    trace("rcWindow: %d,%d - %d,%d\n", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
-    trace("rcClient: %d,%d - %d,%d\n", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
+    if (GetForegroundWindow())
+        ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04x != %04x active %p fg %p\n",
+           info->dwWindowStatus, status, GetActiveWindow(), GetForegroundWindow());
 
     /* win2k and XP return broken border info in GetWindowInfo most of
      * the time, so there is no point in testing it.
@@ -781,6 +783,7 @@ static void test_nonclient_area(HWND hwnd)
     RECT rc_window, rc_client, rc;
     BOOL menu;
     BOOL is_win9x = GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == 0;
+    LRESULT ret;
 
     style = GetWindowLongA(hwnd, GWL_STYLE);
     exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
@@ -809,6 +812,10 @@ static void test_nonclient_area(HWND hwnd)
     trace("calc client: (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom);
     ok(EqualRect(&rc, &rc_client), "client rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d\n", style, exstyle, menu);
 
+    /* NULL rectangle shouldn't crash */
+    ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, 0);
+    ok(ret == 0, "NULL rectangle returned %ld instead of 0\n", ret);
+
     /* Win9x doesn't like WM_NCCALCSIZE with synthetic data and crashes */;
     if (is_win9x)
        return;
@@ -963,12 +970,14 @@ static void test_shell_window(void)
         DWORD pid;
         HANDLE hProcess;
 
+        SetLastError(0xdeadbeef);
         ret = DestroyWindow(shellWindow);
         error = GetLastError();
 
         ok(!ret, "DestroyWindow(shellWindow)\n");
         /* passes on Win XP, but not on Win98 */
-        ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n");
+        ok(error==ERROR_ACCESS_DENIED || error == 0xdeadbeef,
+           "got %u after DestroyWindow(shellWindow)\n", error);
 
         /* close old shell instance */
         GetWindowThreadProcessId(shellWindow, &pid);
@@ -1421,17 +1430,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L
                 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
             AdjustWindowRectEx(&rc, style, 0, exstyle);
             trace("MDI child: calculated max window size = (%d x %d)\n", rc.right-rc.left, rc.bottom-rc.top);
-
-            trace("ptReserved = (%d,%d)\n"
-                  "ptMaxSize = (%d,%d)\n"
-                  "ptMaxPosition = (%d,%d)\n"
-                  "ptMinTrackSize = (%d,%d)\n"
-                  "ptMaxTrackSize = (%d,%d)\n",
-                  minmax->ptReserved.x, minmax->ptReserved.y,
-                  minmax->ptMaxSize.x, minmax->ptMaxSize.y,
-                  minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
-                  minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
-                  minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+            dump_minmax_info( minmax );
 
             ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n",
                minmax->ptMaxSize.x, rc.right - rc.left);
@@ -1440,17 +1439,8 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L
 
             DefMDIChildProcA(hwnd, msg, wparam, lparam);
 
-            trace("DefMDIChildProc returned:\n"
-                  "ptReserved = (%d,%d)\n"
-                  "ptMaxSize = (%d,%d)\n"
-                  "ptMaxPosition = (%d,%d)\n"
-                  "ptMinTrackSize = (%d,%d)\n"
-                  "ptMaxTrackSize = (%d,%d)\n",
-                  minmax->ptReserved.x, minmax->ptReserved.y,
-                  minmax->ptMaxSize.x, minmax->ptMaxSize.y,
-                  minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
-                  minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
-                  minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+            trace("DefMDIChildProc returned:\n");
+            dump_minmax_info( minmax );
 
             MDI_ChildGetMinMaxInfo(client, hwnd, &my_minmax);
             ok(minmax->ptMaxSize.x == my_minmax.ptMaxSize.x, "default width of maximized child %d != %d\n",
@@ -1528,17 +1518,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L
                 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
             AdjustWindowRectEx(&rc, style, 0, exstyle);
             trace("calculated max child window size = (%d x %d)\n", rc.right-rc.left, rc.bottom-rc.top);
-
-            trace("ptReserved = (%d,%d)\n"
-                  "ptMaxSize = (%d,%d)\n"
-                  "ptMaxPosition = (%d,%d)\n"
-                  "ptMinTrackSize = (%d,%d)\n"
-                  "ptMaxTrackSize = (%d,%d)\n",
-                  minmax->ptReserved.x, minmax->ptReserved.y,
-                  minmax->ptMaxSize.x, minmax->ptMaxSize.y,
-                  minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
-                  minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
-                  minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
+            dump_minmax_info( minmax );
 
             ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n",
                minmax->ptMaxSize.x, rc.right - rc.left);
@@ -1899,7 +1879,8 @@ static void test_SetMenu(HWND parent)
     /* test whether we can destroy a menu assigned to a window */
     retok = DestroyMenu(hMenu);
     ok( retok, "DestroyMenu error %d\n", GetLastError());
-    ok(!IsMenu(hMenu), "menu handle should be not valid after DestroyMenu\n");
+    retok = IsMenu(hMenu);
+    ok(!retok || broken(retok) /* nt4 */, "menu handle should be not valid after DestroyMenu\n");
     ret = GetMenu(parent);
     /* This test fails on Win9x */
     if (!is_win9x)
@@ -2060,7 +2041,7 @@ static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner,
     test = GetWindow(hwnd, GW_HWNDNEXT);
     /* skip foreign windows */
     while (test && (GetWindowThreadProcessId(test, NULL) != our_pid ||
-                    ULongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0)))
+                    (void *)(ULONG_PTR)(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0)))
     {
         /*trace("skipping next %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/
         test = GetWindow(test, GW_HWNDNEXT);
@@ -2070,7 +2051,7 @@ static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner,
     test = GetWindow(hwnd, GW_HWNDPREV);
     /* skip foreign windows */
     while (test && (GetWindowThreadProcessId(test, NULL) != our_pid ||
-                    ULongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0)))
+                    (void *)(ULONG_PTR)(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0)))
     {
         /*trace("skipping prev %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/
         test = GetWindow(test, GW_HWNDPREV);
@@ -2197,9 +2178,23 @@ static void test_vis_rgn( HWND hwnd )
     ReleaseDC( hwnd, hdc );
 }
 
+static LRESULT WINAPI set_focus_on_activate_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+    if (msg == WM_ACTIVATE && LOWORD(wp) == WA_ACTIVE)
+    {
+        HWND child = GetWindow(hwnd, GW_CHILD);
+        ok(child != 0, "couldn't find child window\n");
+        SetFocus(child);
+        ok(GetFocus() == child, "Focus should be on child %p\n", child);
+        return 0;
+    }
+    return DefWindowProc(hwnd, msg, wp, lp);
+}
+
 static void test_SetFocus(HWND hwnd)
 {
     HWND child;
+    WNDPROC old_wnd_proc;
 
     /* check if we can set focus to non-visible windows */
 
@@ -2246,22 +2241,47 @@ static void test_SetFocus(HWND hwnd)
     ok( GetFocus() == child, "Focus should still be on child %p\n", child );
     EnableWindow(hwnd, TRUE);
 
+    ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd);
+    ShowWindow(hwnd, SW_SHOWMINIMIZED);
+    ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd);
+todo_wine
+    ok( GetFocus() != child, "Focus should not be on child %p\n", child );
+    ok( GetFocus() != hwnd, "Focus should not be on parent %p\n", hwnd );
+    ShowWindow(hwnd, SW_RESTORE);
+    ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd);
+    ok( GetFocus() == hwnd, "Focus should be on parent %p\n", hwnd );
+    ShowWindow(hwnd, SW_SHOWMINIMIZED);
+    ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd);
+    ok( GetFocus() != child, "Focus should not be on child %p\n", child );
+todo_wine
+    ok( GetFocus() != hwnd, "Focus should not be on parent %p\n", hwnd );
+    old_wnd_proc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)set_focus_on_activate_proc);
+    ShowWindow(hwnd, SW_RESTORE);
+    ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd);
+todo_wine
+    ok( GetFocus() == child, "Focus should be on child %p, not %p\n", child, GetFocus() );
+
+    SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)old_wnd_proc);
+
     DestroyWindow( child );
 }
 
-static void check_wnd_state(HWND active, HWND foreground, HWND focus, HWND capture)
+#define check_wnd_state(a,b,c,d) check_wnd_state_(__FILE__,__LINE__,a,b,c,d)
+static void check_wnd_state_(const char *file, int line,
+                             HWND active, HWND foreground, HWND focus, HWND capture)
 {
-    ok(active == GetActiveWindow(), "GetActiveWindow() = %p\n", GetActiveWindow());
-    if (foreground)
-       ok(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow());
-    ok(focus == GetFocus(), "GetFocus() = %p\n", GetFocus());
-    ok(capture == GetCapture(), "GetCapture() = %p\n", GetCapture());
+    ok_(file, line)(active == GetActiveWindow(), "GetActiveWindow() = %p\n", GetActiveWindow());
+    if (foreground && GetForegroundWindow())
+        ok_(file, line)(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow());
+    ok_(file, line)(focus == GetFocus(), "GetFocus() = %p\n", GetFocus());
+    ok_(file, line)(capture == GetCapture(), "GetCapture() = %p\n", GetCapture());
 }
 
 static void test_SetActiveWindow(HWND hwnd)
 {
     HWND hwnd2;
 
+    flush_events( TRUE );
     ShowWindow(hwnd, SW_HIDE);
     SetFocus(0);
     SetActiveWindow(0);
@@ -2274,10 +2294,12 @@ static void test_SetActiveWindow(HWND hwnd)
 
     hwnd2 = SetActiveWindow(0);
     ok(hwnd2 == hwnd, "SetActiveWindow returned %p instead of %p\n", hwnd2, hwnd);
-    check_wnd_state(0, 0, 0, 0);
-
-    hwnd2 = SetActiveWindow(hwnd);
-    ok(hwnd2 == 0, "SetActiveWindow returned %p instead of 0\n", hwnd2);
+    if (!GetActiveWindow())  /* doesn't always work on vista */
+    {
+        check_wnd_state(0, 0, 0, 0);
+        hwnd2 = SetActiveWindow(hwnd);
+        ok(hwnd2 == 0, "SetActiveWindow returned %p instead of 0\n", hwnd2);
+    }
     check_wnd_state(hwnd, hwnd, hwnd, 0);
 
     SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW);
@@ -2317,6 +2339,7 @@ static void test_SetForegroundWindow(HWND hwnd)
     BOOL ret;
     HWND hwnd2;
 
+    flush_events( TRUE );
     ShowWindow(hwnd, SW_HIDE);
     SetFocus(0);
     SetActiveWindow(0);
@@ -2329,7 +2352,10 @@ static void test_SetForegroundWindow(HWND hwnd)
 
     hwnd2 = SetActiveWindow(0);
     ok(hwnd2 == hwnd, "SetActiveWindow(0) returned %p instead of %p\n", hwnd2, hwnd);
-    check_wnd_state(0, 0, 0, 0);
+    if (GetActiveWindow() == hwnd)  /* doesn't always work on vista */
+        check_wnd_state(hwnd, hwnd, hwnd, 0);
+    else
+        check_wnd_state(0, 0, 0, 0);
 
     ret = SetForegroundWindow(hwnd);
     ok(ret, "SetForegroundWindow returned FALSE instead of TRUE\n");
@@ -2338,7 +2364,9 @@ static void test_SetForegroundWindow(HWND hwnd)
     SetLastError(0xdeadbeef);
     ret = SetForegroundWindow(0);
     ok(!ret, "SetForegroundWindow returned TRUE instead of FALSE\n");
-    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got error %d expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError());
+    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
+       broken(GetLastError() == 0xdeadbeef),  /* win9x */
+       "got error %d expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError());
     check_wnd_state(hwnd, hwnd, hwnd, 0);
 
     SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW);
@@ -2440,7 +2468,10 @@ static LRESULT WINAPI button_hook_proc(HWND button, UINT msg, WPARAM wparam, LPA
 
 static void test_capture_1(void)
 {
-    HWND button, capture;
+    HWND button, capture, oldFocus, oldActive;
+
+    oldFocus = GetFocus();
+    oldActive = GetActiveWindow();
 
     capture = GetCapture();
     ok(capture == 0, "GetCapture() = %p\n", capture);
@@ -2458,14 +2489,16 @@ static void test_capture_1(void)
     check_wnd_state(button, 0, button, button);
 
     DestroyWindow(button);
-    check_wnd_state(0, 0, 0, 0);
+    check_wnd_state(oldActive, 0, oldFocus, 0);
 }
 
 static void test_capture_2(void)
 {
-    HWND button, hwnd, capture;
+    HWND button, hwnd, capture, oldFocus, oldActive;
 
-    check_wnd_state(0, 0, 0, 0);
+    oldFocus = GetFocus();
+    oldActive = GetActiveWindow();
+    check_wnd_state(oldActive, 0, oldFocus, 0);
 
     button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
     assert(button);
@@ -2515,7 +2548,7 @@ static void test_capture_2(void)
     check_wnd_state(button, button, button, 0);
 
     DestroyWindow(button);
-    check_wnd_state(0, 0, 0, 0);
+    check_wnd_state(oldActive, 0, oldFocus, 0);
 }
 
 static void test_capture_3(HWND hwnd1, HWND hwnd2)
@@ -2548,7 +2581,8 @@ static void test_keyboard_input(HWND hwnd)
     MSG msg;
     BOOL ret;
 
-    ShowWindow(hwnd, SW_SHOW);
+    flush_events( TRUE );
+    SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW);
     UpdateWindow(hwnd);
     flush_events( TRUE );
 
@@ -2645,12 +2679,19 @@ static void test_mouse_input(HWND hwnd)
 
     flush_events( TRUE );
 
-    /* Check that setting the same position will generate WM_MOUSEMOVE */
+    /* Check that setting the same position may generate WM_MOUSEMOVE */
     SetCursorPos(x, y);
     msg.message = 0;
-    ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
-    ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
-    ok(msg.pt.x == x && msg.pt.y == y, "wrong message coords (%d,%d)/(%d,%d)\n", x, y, msg.pt.x, msg.pt.y);
+    do
+        ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
+    while (ret && msg.message >= 0xc000);  /* skip registered messages */
+    if (ret)
+    {
+        ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n",
+           msg.hwnd, msg.message);
+        ok(msg.pt.x == x && msg.pt.y == y, "wrong message coords (%d,%d)/(%d,%d)\n",
+           x, y, msg.pt.x, msg.pt.y);
+    }
 
     /* force the system to update its internal queue mouse position,
      * otherwise it won't generate relative mouse movements below.
@@ -2660,23 +2701,29 @@ static void test_mouse_input(HWND hwnd)
 
     msg.message = 0;
     mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0);
-    ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
-    ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
     /* FIXME: SetCursorPos in Wine generates additional WM_MOUSEMOVE message */
-    if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
-        ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+    {
+        if (msg.message >= 0xc000) continue;  /* skip registered messages */
+        ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE,
+           "hwnd %p message %04x\n", msg.hwnd, msg.message);
+    }
     ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
     ok( !ret, "message %04x available\n", msg.message);
 
     mouse_event(MOUSEEVENTF_MOVE, -1, -1, 0, 0);
     ShowWindow(popup, SW_HIDE);
-    ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
+    do
+        ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
+    while (msg.message >= 0xc000);  /* skip registered messages */
     ok(msg.hwnd == hwnd && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message);
     flush_events( TRUE );
 
     mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0);
     ShowWindow(hwnd, SW_HIDE);
-    ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
+    do
+        ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
+    while (ret && msg.message >= 0xc000);  /* skip registered messages */
     ok( !ret, "message %04x available\n", msg.message);
     flush_events( TRUE );
 
@@ -2742,7 +2789,9 @@ static void test_mouse_input(HWND hwnd)
     SendMessageA(hwnd, WM_COMMAND, (WPARAM)popup, 0);
     test_lbuttondown_flag = FALSE;
 
-    ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
+    do
+        ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
+    while (msg.message >= 0xc000);  /* skip registered messages */
     ok(msg.hwnd == popup && msg.message == WM_LBUTTONDOWN, "hwnd %p/%p message %04x\n",
        msg.hwnd, popup, msg.message);
     ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n");
@@ -3219,7 +3268,12 @@ static void test_scroll(void)
         100, 100, 200, 200, 0, 0, 0, NULL);
     /* horizontal */
     ret = GetScrollRange( hwnd, SB_HORZ, &min, &max);
-    ok( ret, "GetScrollRange returns FALSE\n");
+    if (!ret)  /* win9x */
+    {
+        win_skip( "GetScrollRange doesn't work\n" );
+        DestroyWindow( hwnd);
+        return;
+    }
     ok( min == 0, "minimum scroll pos is %d (should be zero)\n", min);
     ok( max == 0, "maximum scroll pos is %d (should be zero)\n", min);
     si.cbSize = sizeof( si);
@@ -3321,9 +3375,17 @@ static void test_params(void)
     INT rc;
 
     /* Just a param check */
-    SetLastError(0xdeadbeef);
-    rc = GetWindowText(hwndMain2, NULL, 1024);
-    ok( rc==0, "GetWindowText: rc=%d err=%d\n",rc,GetLastError());
+    if (pGetMonitorInfoA)
+    {
+        SetLastError(0xdeadbeef);
+        rc = GetWindowText(hwndMain2, NULL, 1024);
+        ok( rc==0, "GetWindowText: rc=%d err=%d\n",rc,GetLastError());
+    }
+    else
+    {
+        /* Skips actually on Win95 and NT4 */
+        win_skip("Test would crash on Win95\n");
+    }
 
     SetLastError(0xdeadbeef);
     hwnd=CreateWindow("LISTBOX", "TestList",
@@ -3898,7 +3960,7 @@ static LRESULT CALLBACK minmax_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM l
 }
 
 static int expected_cx, expected_cy;
-static RECT expected_rect;
+static RECT expected_rect, broken_rect;
 
 static LRESULT CALLBACK winsizes_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
 {
@@ -3920,10 +3982,16 @@ static LRESULT CALLBACK winsizes_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM
         GetWindowRect( hwnd, &rect );
         trace( "hwnd %p msg %x size %dx%d rect %d,%d-%d,%d\n",
                hwnd, msg, cs->cx, cs->cy, rect.left, rect.top, rect.right, rect.bottom );
-        ok( cs->cx == expected_cx, "wrong x size %d/%d\n", cs->cx, expected_cx );
-        ok( cs->cy == expected_cy, "wrong y size %d/%d\n", cs->cy, expected_cy );
-        ok( rect.right - rect.left == expected_rect.right - expected_rect.left &&
-            rect.bottom - rect.top == expected_rect.bottom - expected_rect.top,
+        ok( cs->cx == expected_cx || broken(cs->cx == (short)expected_cx),
+            "wrong x size %d/%d\n", cs->cx, expected_cx );
+        ok( cs->cy == expected_cy || broken(cs->cy == (short)expected_cy),
+            "wrong y size %d/%d\n", cs->cy, expected_cy );
+        ok( (rect.right - rect.left == expected_rect.right - expected_rect.left &&
+             rect.bottom - rect.top == expected_rect.bottom - expected_rect.top) ||
+            broken( rect.right - rect.left == broken_rect.right - broken_rect.left &&
+                    rect.bottom - rect.top == broken_rect.bottom - broken_rect.top) ||
+            broken( rect.right - rect.left == (short)broken_rect.right - (short)broken_rect.left &&
+                    rect.bottom - rect.top == (short)broken_rect.bottom - (short)broken_rect.top),
             "wrong rect %d,%d-%d,%d / %d,%d-%d,%d\n",
             rect.left, rect.top, rect.right, rect.bottom,
             expected_rect.left, expected_rect.top, expected_rect.right, expected_rect.bottom );
@@ -3961,6 +4029,11 @@ static void test_CreateWindow(void)
 #define expect_ex_style(window, ex_style)\
     ok(GetWindowLong(window, GWL_EXSTYLE) == (ex_style), "expected ex_style %x != %x\n", (LONG)(ex_style), GetWindowLong(window, GWL_EXSTYLE))
 
+#define expect_gle_broken_9x(gle)\
+    ok(GetLastError() == gle ||\
+       broken(GetLastError() == 0xdeadbeef),\
+       "IsMenu set error %d\n", GetLastError())
+
     hmenu = CreateMenu();
     assert(hmenu != 0);
     parent = GetDesktopWindow();
@@ -4017,7 +4090,7 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4031,7 +4104,7 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4045,7 +4118,7 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4059,14 +4132,16 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     /* WS_CHILD | WS_POPUP */
     SetLastError(0xdeadbeef);
     hwnd = CreateWindowEx(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP,
                            0, 0, 100, 100, parent, (HMENU)1, 0, NULL);
-    ok(!hwnd, "CreateWindowEx should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n");
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
+    if (hwnd)
+        DestroyWindow(hwnd);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4080,13 +4155,15 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     SetLastError(0xdeadbeef);
     hwnd = CreateWindowEx(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION,
                            0, 0, 100, 100, parent, (HMENU)1, 0, NULL);
-    ok(!hwnd, "CreateWindowEx should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n");
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
+    if (hwnd)
+        DestroyWindow(hwnd);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4100,13 +4177,15 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     SetLastError(0xdeadbeef);
     hwnd = CreateWindowEx(0, "static", NULL, WS_CHILD | WS_POPUP,
                            0, 0, 100, 100, parent, (HMENU)1, 0, NULL);
-    ok(!hwnd, "CreateWindowEx should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n");
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
+    if (hwnd)
+        DestroyWindow(hwnd);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4120,13 +4199,15 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     SetLastError(0xdeadbeef);
     hwnd = CreateWindowEx(0, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION,
                            0, 0, 100, 100, parent, (HMENU)1, 0, NULL);
-    ok(!hwnd, "CreateWindowEx should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n");
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
+    if (hwnd)
+        DestroyWindow(hwnd);
 
     hmenu = CreateMenu();
     assert(hmenu != 0);
@@ -4140,7 +4221,7 @@ static void test_CreateWindow(void)
     DestroyWindow(hwnd);
     SetLastError(0xdeadbeef);
     ok(!IsMenu(hmenu), "IsMenu should fail\n");
-    ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError());
+    expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE);
 
     /* test child window sizing */
     cls.style = 0;
@@ -4204,15 +4285,17 @@ static void test_CreateWindow(void)
 
     expected_cx = expected_cy = 200000;
     SetRect( &expected_rect, 0, 0, 200000, 200000 );
+    broken_rect = expected_rect;
     hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 300000, 300000, 200000, 200000, parent, 0, 0, NULL);
     ok( hwnd != 0, "creation failed err %u\n", GetLastError());
     GetClientRect( hwnd, &rc );
-    ok( rc.right == 200000, "invalid rect right %u\n", rc.right );
-    ok( rc.bottom == 200000, "invalid rect bottom %u\n", rc.bottom );
+    ok( rc.right == 200000 || broken(rc.right == (short)200000), "invalid rect right %u\n", rc.right );
+    ok( rc.bottom == 200000 || broken(rc.bottom == (short)200000), "invalid rect bottom %u\n", rc.bottom );
     DestroyWindow(hwnd);
 
     expected_cx = expected_cy = -10;
     SetRect( &expected_rect, 0, 0, 0, 0 );
+    SetRect( &broken_rect, 0, 0, -10, -10 );
     hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -20, -20, -10, -10, parent, 0, 0, NULL);
     ok( hwnd != 0, "creation failed err %u\n", GetLastError());
     GetClientRect( hwnd, &rc );
@@ -4222,6 +4305,7 @@ static void test_CreateWindow(void)
 
     expected_cx = expected_cy = -200000;
     SetRect( &expected_rect, 0, 0, 0, 0 );
+    SetRect( &broken_rect, 0, 0, -200000, -200000 );
     hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -300000, -300000, -200000, -200000, parent, 0, 0, NULL);
     ok( hwnd != 0, "creation failed err %u\n", GetLastError());
     GetClientRect( hwnd, &rc );
@@ -4229,6 +4313,33 @@ static void test_CreateWindow(void)
     ok( rc.bottom == 0, "invalid rect bottom %u\n", rc.bottom );
     DestroyWindo