Autosyncing with Wine HEAD
authorThe Wine Synchronizer <winesync@svn.reactos.org>
Sat, 1 Dec 2007 18:29:29 +0000 (18:29 +0000)
committerThe Wine Synchronizer <winesync@svn.reactos.org>
Sat, 1 Dec 2007 18:29:29 +0000 (18:29 +0000)
svn path=/trunk/; revision=30937

29 files changed:
rostests/winetests/comctl32/bmp128x15.bmp [new file with mode: 0644]
rostests/winetests/comctl32/bmp80x15.bmp [new file with mode: 0644]
rostests/winetests/comctl32/comboex.c
rostests/winetests/comctl32/comctl32.rbuild
rostests/winetests/comctl32/comctl32_ros.diff [new file with mode: 0644]
rostests/winetests/comctl32/datetime.c [new file with mode: 0644]
rostests/winetests/comctl32/dpa.c
rostests/winetests/comctl32/header.c
rostests/winetests/comctl32/imagelist.c
rostests/winetests/comctl32/listview.c
rostests/winetests/comctl32/misc.c [new file with mode: 0644]
rostests/winetests/comctl32/monthcal.c
rostests/winetests/comctl32/mru.c
rostests/winetests/comctl32/msg.c [new file with mode: 0644]
rostests/winetests/comctl32/msg.h [new file with mode: 0644]
rostests/winetests/comctl32/progress.c
rostests/winetests/comctl32/propsheet.c
rostests/winetests/comctl32/rebar.c [new file with mode: 0644]
rostests/winetests/comctl32/resources.h [new file with mode: 0644]
rostests/winetests/comctl32/rsrc.rc [moved from rostests/winetests/comctl32/propsheet.rc with 68% similarity]
rostests/winetests/comctl32/status.c [new file with mode: 0644]
rostests/winetests/comctl32/subclass.c
rostests/winetests/comctl32/tab.c
rostests/winetests/comctl32/testlist.c
rostests/winetests/comctl32/toolbar.c
rostests/winetests/comctl32/tooltips.c
rostests/winetests/comctl32/trackbar.c [new file with mode: 0644]
rostests/winetests/comctl32/treeview.c
rostests/winetests/comctl32/updown.c

diff --git a/rostests/winetests/comctl32/bmp128x15.bmp b/rostests/winetests/comctl32/bmp128x15.bmp
new file mode 100644 (file)
index 0000000..85061b4
Binary files /dev/null and b/rostests/winetests/comctl32/bmp128x15.bmp differ
diff --git a/rostests/winetests/comctl32/bmp80x15.bmp b/rostests/winetests/comctl32/bmp80x15.bmp
new file mode 100644 (file)
index 0000000..c524d71
Binary files /dev/null and b/rostests/winetests/comctl32/bmp80x15.bmp differ
index 3743c07..8f436ca 100644 (file)
@@ -82,108 +82,108 @@ static void test_comboboxex(void) {
                  out_of_range_item[] = {'O','u','t',' ','o','f',' ','R','a','n','g','e',' ','I','t','e','m',0};
 
     /* Allocate space for result */
-    textBuffer = malloc(MAX_CHARS);
+    textBuffer = HeapAlloc(GetProcessHeap(), 0, MAX_CHARS);
 
     /* Basic comboboxex test */
     myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
 
     /* Add items onto the end of the combobox */
     res = addItem(myHwnd, -1, first_item);
-    ok(res == 0, "Adding simple item failed (%ld)\n", res);
+    ok(res == 0, "Adding simple item failed (%d)\n", res);
     res = addItem(myHwnd, -1, second_item);
-    ok(res == 1, "Adding simple item failed (%ld)\n", res);
+    ok(res == 1, "Adding simple item failed (%d)\n", res);
     res = addItem(myHwnd, 2, third_item);
-    ok(res == 2, "Adding simple item failed (%ld)\n", res);
+    ok(res == 2, "Adding simple item failed (%d)\n", res);
     res = addItem(myHwnd, 1, middle_item);
-    ok(res == 1, "Inserting simple item failed (%ld)\n", res);
+    ok(res == 1, "Inserting simple item failed (%d)\n", res);
 
     /* Add an item completely out of range */
     res = addItem(myHwnd, 99, out_of_range_item);
-    ok(res == -1, "Adding using out of range index worked unexpectedly (%ld)\n", res);
+    ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
     res = addItem(myHwnd, 5, out_of_range_item);
-    ok(res == -1, "Adding using out of range index worked unexpectedly (%ld)\n", res);
+    ok(res == -1, "Adding using out of range index worked unexpectedly (%d)\n", res);
     /* Removed: Causes traps on Windows XP
        res = addItem(myHwnd, -2, "Out Of Range Item");
        ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res);
      */
 
-    /* Get an item completely out of range */
-    res = getItem(myHwnd, 99, &cbexItem);
-    ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText);
-    res = getItem(myHwnd, 4, &cbexItem);
-    ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText);
-    res = getItem(myHwnd, -2, &cbexItem);
-    ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText);
-
-    /* Get an item in range */
-    res = getItem(myHwnd, 0, &cbexItem);
-    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    /* Get an item completely out of range */ 
+    res = getItem(myHwnd, 99, &cbexItem); 
+    ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
+    res = getItem(myHwnd, 4, &cbexItem); 
+    ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
+    res = getItem(myHwnd, -2, &cbexItem); 
+    ok(res == 0, "Getting item using out of range index worked unexpectedly (%d, %s)\n", res, cbexItem.pszText);
+
+    /* Get an item in range */ 
+    res = getItem(myHwnd, 0, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
     ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
 
-    res = getItem(myHwnd, 1, &cbexItem);
-    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    res = getItem(myHwnd, 1, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
     ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
 
-    res = getItem(myHwnd, 2, &cbexItem);
-    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    res = getItem(myHwnd, 2, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
     ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
 
-    res = getItem(myHwnd, 3, &cbexItem);
-    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    res = getItem(myHwnd, 3, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%d)\n", res);
     ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
 
-    /* Set an item completely out of range */
-    res = setItem(myHwnd, 99, replacement_item);
-    ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res);
-    res = setItem(myHwnd, 4, replacement_item);
-    ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res);
-    res = setItem(myHwnd, -2, replacement_item);
-    ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res);
+    /* Set an item completely out of range */ 
+    res = setItem(myHwnd, 99, replacement_item); 
+    ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
+    res = setItem(myHwnd, 4, replacement_item); 
+    ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
+    res = setItem(myHwnd, -2, replacement_item); 
+    ok(res == 0, "Setting item using out of range index worked unexpectedly (%d)\n", res);
 
-    /* Set an item in range */
+    /* Set an item in range */ 
     res = setItem(myHwnd, 0, replacement_item);
-    ok(res != 0, "Setting first item failed (%ld)\n", res);
+    ok(res != 0, "Setting first item failed (%d)\n", res);
     res = setItem(myHwnd, 3, replacement_item);
-    ok(res != 0, "Setting last item failed (%ld)\n", res);
+    ok(res != 0, "Setting last item failed (%d)\n", res);
 
     /* Remove items completely out of range (4 items in control at this point) */
     res = delItem(myHwnd, -1);
-    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res);
+    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
     res = delItem(myHwnd, 4);
-    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res);
+    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
 
     /* Remove items in range (4 items in control at this point) */
     res = delItem(myHwnd, 3);
-    ok(res == 3, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res == 3, "Deleting using out of range index failed (%d)\n", res);
     res = delItem(myHwnd, 0);
-    ok(res == 2, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res == 2, "Deleting using out of range index failed (%d)\n", res);
     res = delItem(myHwnd, 0);
-    ok(res == 1, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res == 1, "Deleting using out of range index failed (%d)\n", res);
     res = delItem(myHwnd, 0);
-    ok(res == 0, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res == 0, "Deleting using out of range index failed (%d)\n", res);
 
     /* Remove from an empty box */
     res = delItem(myHwnd, 0);
-    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res);
+    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%d)\n", res);
 
 
     /* Cleanup */
-    free(textBuffer);
+    HeapFree(GetProcessHeap(), 0, textBuffer);
 
 }
 
-LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     switch(msg) {
 
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
-
+  
     default:
         return DefWindowProcA(hWnd, msg, wParam, lParam);
     }
-
+    
     return 0L;
 }
 
@@ -200,14 +200,14 @@ static void init(void) {
     wc.cbWndExtra = 0;
     wc.hInstance = GetModuleHandleA(NULL);
     wc.hIcon = NULL;
-    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
     wc.lpszClassName = ComboExTestClass;
     wc.lpfnWndProc = ComboExTestWndProc;
     RegisterClassA(&wc);
 
-    hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW,
+    hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW, 
       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
     assert(hComboExParentWnd != NULL);
 
@@ -218,13 +218,13 @@ static void init(void) {
 static void cleanup(void)
 {
     MSG msg;
-
+    
     PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0);
     while (GetMessageA(&msg,0,0,0)) {
         TranslateMessage(&msg);
         DispatchMessageA(&msg);
     }
-
+    
     UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
 }
 
index 407eac3..07d9b34 100644 (file)
@@ -1,29 +1,39 @@
-<module name="comctl32_winetest" type="win32cui" installbase="bin" installname="comctl32_winetest.exe" allowwarnings="true">
-    <include base="comctl32_winetest">.</include>
-    <define name="__USE_W32API" />
-    <library>shlwapi</library>
-    <library>ole32</library>
-    <library>comctl32</library>
-    <library>ntdll</library>
-    <library>gdi32</library>
-    <library>user32</library>
-    <library>kernel32</library>
-    <library>advapi32</library>
-    <file>comboex.c</file>
-    <file>dpa.c</file>
-    <file>header.c</file>
-    <file>imagelist.c</file>
-    <file>listview.c</file>
-    <file>monthcal.c</file>
-    <file>mru.c</file>
-    <file>progress.c</file>
-    <file>propsheet.c</file>
-    <file>subclass.c</file>
-    <file>tab.c</file>
-    <file>testlist.c</file>
-    <file>toolbar.c</file>
-    <file>tooltips.c</file>
-    <file>treeview.c</file>
-    <file>updown.c</file>
-    <file>propsheet.rc</file>
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<module name="comctl32_winetest" type="win32cui" installbase="bin" installname="comctl32_winetest.exe" allowwarnings="true" entrypoint="0">
+       <include base="comctl32_winetest">.</include>
+       <define name="WINVER">0x600</define>
+       <define name="_WIN32_WINNT">0x600</define>
+       <library>wine</library>
+       <library>comctl32</library>
+       <library>ole32</library>
+       <library>shlwapi</library>
+       <library>user32</library>
+       <library>gdi32</library>
+       <library>advapi32</library>
+       <library>kernel32</library>
+       <library>ntdll</library>
+       <file>comboex.c</file>
+       <file>datetime.c</file>
+       <file>dpa.c</file>
+       <file>header.c</file>
+       <file>imagelist.c</file>
+       <file>listview.c</file>
+       <file>misc.c</file>
+       <file>monthcal.c</file>
+       <file>mru.c</file>
+       <file>msg.c</file>
+       <file>progress.c</file>
+       <file>propsheet.c</file>
+       <file>rebar.c</file>
+       <file>status.c</file>
+       <file>subclass.c</file>
+       <file>tab.c</file>
+       <file>toolbar.c</file>
+       <file>tooltips.c</file>
+       <file>trackbar.c</file>
+       <file>treeview.c</file>
+       <file>updown.c</file>
+       <file>rsrc.rc</file>
+       <file>testlist.c</file>
 </module>
diff --git a/rostests/winetests/comctl32/comctl32_ros.diff b/rostests/winetests/comctl32/comctl32_ros.diff
new file mode 100644 (file)
index 0000000..4dfe3b1
--- /dev/null
@@ -0,0 +1,24 @@
+Index: dpa.c
+===================================================================
+--- dpa.c      (revision 25766)
++++ dpa.c      (working copy)
+@@ -25,6 +25,7 @@
+ #include "windef.h"
+ #include "winbase.h"
++#include "wingdi.h"
+ #include "winuser.h"
+ #include "commctrl.h"
+ #include "objidl.h"
+Index: monthcal.c
+===================================================================
+--- monthcal.c (revision 25766)
++++ monthcal.c (working copy)
+@@ -23,6 +23,7 @@
+ #include "windef.h"
+ #include "winbase.h"
++#include "wingdi.h"
+ #include "winuser.h"
+ #include "commctrl.h"
diff --git a/rostests/winetests/comctl32/datetime.c b/rostests/winetests/comctl32/datetime.c
new file mode 100644 (file)
index 0000000..1a8afd1
--- /dev/null
@@ -0,0 +1,571 @@
+/* Unit test suite for datetime control.
+*
+* Copyright 2007 Kanit Therdsteerasukdi
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+#include "msg.h"
+
+#define expect(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d, got %ld\n", (EXPECTED), (GOT))
+
+#define expect_unsuccess(EXPECTED, GOT) ok((GOT)==(EXPECTED), "Expected %d(unsuccessful), got %ld(successful)\n", (EXPECTED), (GOT))
+
+#define NUM_MSG_SEQUENCES   1
+#define DATETIME_SEQ_INDEX    0
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message test_dtm_set_format_seq[] = {
+    { DTM_SETFORMATA, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { DTM_SETFORMATA, sent|wparam, 0x00000000 },
+    { 0 }
+};
+
+static const struct message test_dtm_set_and_get_mccolor_seq[] = {
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00dcb464 },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00ffffff },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00dcb464 },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000004, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00ffffff },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00dcb464 },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000001, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00ffffff },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00dcb464 },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000002, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00ffffff },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00dcb464 },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000003, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00000000 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00ffffff },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00dcb464 },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, 0x00000005, 0x00000000 },
+    { 0 }
+};
+
+static const struct message test_dtm_set_and_get_mcfont_seq[] = {
+    { DTM_SETMCFONT, sent|lparam, 0, 0x00000001 },
+    { DTM_GETMCFONT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message test_dtm_get_monthcal_seq[] = {
+    { DTM_GETMONTHCAL, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message test_dtm_set_and_get_range_seq[] = {
+    { DTM_SETRANGE, sent|wparam, 0x00000001 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000002 },
+    { DTM_SETRANGE, sent|wparam, 0x00000002 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000},
+    { DTM_SETRANGE, sent|wparam, 0x00000001 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { 0 }
+};
+
+static const struct message test_dtm_set_range_swap_min_max_seq[] = {
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { DTM_SETRANGE, sent|wparam, 0x00000003 },
+    { DTM_GETRANGE, sent|wparam, 0x00000000 },
+    { 0 }
+};
+
+static const struct message test_dtm_set_and_get_system_time_seq[] = {
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 },
+    { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000000 },
+    { 0 }
+};
+
+static const struct message destroy_window_seq[] = {
+    { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("datetime: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, DATETIME_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND create_datetime_control(DWORD style, DWORD exstyle)
+{
+    struct subclass_info *info;
+    HWND hWndDateTime = NULL;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    hWndDateTime = CreateWindowEx(0,
+        DATETIMEPICK_CLASS,
+        NULL,
+        style,
+        0,50,300,120,
+        NULL,
+        NULL,
+        NULL,
+        NULL);
+
+    if (!hWndDateTime) {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC,
+                                            (LONG_PTR)datetime_subclass_proc);
+    SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)info);
+
+    return hWndDateTime;
+}
+
+static void test_dtm_set_format(HWND hWndDateTime)
+{
+    LRESULT r;
+
+    r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, (LPARAM)NULL);
+    expect(1, r);
+
+    r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0,
+                   (LPARAM)"'Today is: 'hh':'m':'s dddd MMM dd', 'yyyy");
+    expect(1, r);
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
+{
+    LRESULT r;
+    COLORREF theColor, prevColor;
+
+    theColor=RGB(0,0,0);
+    r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
+    ok(r != -1, "%s: Set RGB(0,0,0): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
+    prevColor=theColor;
+    theColor=RGB(255,255,255);
+    r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
+    ok(r==prevColor, "%s: Set RGB(255,255,255): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
+    prevColor=theColor;
+    theColor=RGB(100,180,220);
+    r = SendMessage(hWndDateTime, DTM_SETMCCOLOR, mccolor_type, theColor);
+    ok(r==prevColor, "%s: Set RGB(100,180,220): Expected COLORREF of previous value, got %ld\n", mccolor_name, r);
+    r = SendMessage(hWndDateTime, DTM_GETMCCOLOR, mccolor_type, 0);
+    ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r);
+}
+
+static void test_dtm_set_and_get_mccolor(HWND hWndDateTime)
+{
+    test_mccolor_types(hWndDateTime, MCSC_BACKGROUND, "MCSC_BACKGROUND");
+    test_mccolor_types(hWndDateTime, MCSC_MONTHBK, "MCSC_MONTHBK");
+    test_mccolor_types(hWndDateTime, MCSC_TEXT, "MCSC_TEXT");
+    test_mccolor_types(hWndDateTime, MCSC_TITLEBK, "MCSC_TITLEBK");
+    test_mccolor_types(hWndDateTime, MCSC_TITLETEXT, "MCSC_TITLETEXT");
+    test_mccolor_types(hWndDateTime, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+static void test_dtm_set_and_get_mcfont(HWND hWndDateTime)
+{
+    HFONT hFontOrig, hFontNew;
+
+    hFontOrig = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+    SendMessage(hWndDateTime, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
+    hFontNew = (HFONT)SendMessage(hWndDateTime, DTM_GETMCFONT, 0, 0);
+    ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew);
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mcfont_seq, "test_dtm_set_and_get_mcfont", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+static void test_dtm_get_monthcal(HWND hWndDateTime)
+{
+    LRESULT r;
+
+    todo_wine {
+        r = SendMessage(hWndDateTime, DTM_GETMONTHCAL, 0, 0);
+        ok(r == (LPARAM)NULL, "Expected NULL(no child month calendar control), got %ld\n", r);
+    }
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
+{
+    st->wYear = year;
+    st->wMonth = month;
+    st->wDayOfWeek = dayofweek;
+    st->wDay = day;
+    st->wHour = hour;
+    st->wMinute = minute;
+    st->wSecond = second;
+    st->wMilliseconds = milliseconds;
+}
+
+static LPARAM compare_systime_date(SYSTEMTIME *st1, SYSTEMTIME *st2)
+{
+    return (st1->wYear == st2->wYear)
+            && (st1->wMonth == st2->wMonth)
+            && (st1->wDayOfWeek == st2->wDayOfWeek)
+            && (st1->wDay == st2->wDay);
+}
+
+static LPARAM compare_systime_time(SYSTEMTIME *st1, SYSTEMTIME *st2)
+{
+    return (st1->wHour == st2->wHour)
+            && (st1->wMinute == st2->wMinute)
+            && (st1->wSecond == st2->wSecond)
+            && (st1->wMilliseconds == st2->wMilliseconds);
+}
+
+static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
+{
+    if(!compare_systime_date(st1, st2))
+        return 0;
+
+    return compare_systime_time(st1, st2);
+}
+
+#define expect_systime(ST1, ST2) ok(compare_systime((ST1), (ST2))==1, "ST1 != ST2\n")
+#define expect_systime_date(ST1, ST2) ok(compare_systime_date((ST1), (ST2))==1, "ST1.date != ST2.date\n")
+#define expect_systime_time(ST1, ST2) ok(compare_systime_time((ST1), (ST2))==1, "ST1.time != ST2.time\n")
+
+static void test_dtm_set_and_get_range(HWND hWndDateTime)
+{
+    LRESULT r;
+    SYSTEMTIME st[2];
+    SYSTEMTIME getSt[2];
+
+    /* initialize st[0] to lowest possible value */
+    fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
+    /* intialize st[1] to all invalid numbers */
+    fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == GDTR_MIN, "Expected %x, not %x(GDTR_MAX) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MIN, GDTR_MAX, GDTR_MIN | GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[0]);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
+    expect_unsuccess(0, r);
+
+    /* set st[0] to all invalid numbers */
+    fill_systime_struct(&st[0], 0, 0, 7, 0, 24, 60, 60, 1000);
+    /* set st[1] to highest possible value */
+    fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    todo_wine {
+        ok(r == GDTR_MAX, "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MIN | GDTR_MAX), got %lx\n", GDTR_MAX, GDTR_MIN, GDTR_MIN | GDTR_MAX, r);
+    }
+    expect_systime(&st[1], &getSt[1]);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
+    expect_unsuccess(0, r);
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect_unsuccess(0, r);
+
+    /* set st[0] to highest possible value */
+    fill_systime_struct(&st[0], 30827, 12, 6, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[0]);
+    expect_systime(&st[1], &getSt[1]);
+
+    /* initialize st[0] to lowest possible value */
+    fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
+    /* set st[1] to highest possible value */
+    fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[0]);
+    expect_systime(&st[1], &getSt[1]);
+
+    /* set st[0] to value higher than minimum */
+    fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
+    /* set st[1] to value lower than maximum */
+    fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[0]);
+    expect_systime(&st[1], &getSt[1]);
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_range_seq, "test_dtm_set_and_get_range", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+/* when max<min for DTM_SETRANGE, Windows seems to swap the min and max values,
+although that's undocumented.  However, it doesn't seem to be implemented
+correctly, causing some strange side effects */
+static void test_dtm_set_range_swap_min_max(HWND hWndDateTime)
+{
+    LRESULT r;
+    SYSTEMTIME st[2];
+    SYSTEMTIME getSt[2];
+    SYSTEMTIME origSt;
+
+    fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
+    ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
+    expect_systime(&st[0], &origSt);
+
+    /* set st[0] to value higher than st[1] */
+    fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
+    fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
+
+    /* since min>max, min and max values should be swapped by DTM_SETRANGE
+    automatically */
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    todo_wine {
+        expect_systime(&st[0], &getSt[0]);
+    }
+    todo_wine {
+        expect_systime(&st[1], &getSt[1]);
+    }
+
+    fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
+    ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
+    /* the time part seems to not change after swapping the min and max values
+    and doing DTM_SETSYSTEMTIME */
+    expect_systime_date(&st[0], &getSt[0]);
+    todo_wine {
+        expect_systime_time(&origSt, &getSt[0]);
+    }
+
+    /* set st[0] to value higher than minimum */
+    fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
+    /* set st[1] to value lower than maximum */
+    fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    /* for some reason after we swapped the min and max values before,
+    whenever we do a DTM_SETRANGE, the DTM_GETRANGE will return the values
+    swapped*/
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    todo_wine {
+        expect_systime(&st[0], &getSt[1]);
+    }
+    todo_wine {
+        expect_systime(&st[1], &getSt[0]);
+    }
+
+    /* set st[0] to value higher than st[1] */
+    fill_systime_struct(&st[0], 2007, 3, 2, 31, 23, 59, 59, 999);
+    fill_systime_struct(&st[1], 1980, 1, 3, 23, 14, 34, 37, 465);
+
+    /* set min>max again, so that the return values of DTM_GETRANGE are no
+    longer swapped the next time we do a DTM SETRANGE and DTM_GETRANGE*/
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[1]);
+    expect_systime(&st[1], &getSt[0]);
+
+    /* initialize st[0] to lowest possible value */
+    fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
+    /* set st[1] to highest possible value */
+    fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    ok(r == (GDTR_MIN | GDTR_MAX), "Expected %x, not %x(GDTR_MIN) or %x(GDTR_MAX), got %lx\n", (GDTR_MIN | GDTR_MAX), GDTR_MIN, GDTR_MAX, r);
+    expect_systime(&st[0], &getSt[0]);
+    expect_systime(&st[1], &getSt[1]);
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_range_swap_min_max_seq, "test_dtm_set_range_swap_min_max", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+static void test_dtm_set_and_get_system_time(HWND hWndDateTime)
+{
+    LRESULT r;
+    SYSTEMTIME st;
+    SYSTEMTIME getSt;
+    HWND hWndDateTime_test_gdt_none;
+
+    hWndDateTime_test_gdt_none = create_datetime_control(0, 0);
+
+    ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none);
+    if(hWndDateTime_test_gdt_none) {
+        r = SendMessage(hWndDateTime_test_gdt_none, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
+        expect(0, r);
+    }
+    else {
+        skip("hWndDateTime_test_gdt_none is NULL\n");
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        return;
+    }
+
+    DestroyWindow(hWndDateTime_test_gdt_none);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    ok(r == GDT_NONE, "Expected %d, not %d(GDT_VALID) or %d(GDT_ERROR), got %ld\n", GDT_NONE, GDT_VALID, GDT_ERROR, r);
+
+    /* set st to lowest possible value */
+    fill_systime_struct(&st, 1601, 1, 0, 1, 0, 0, 0, 0);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(1, r);
+
+    /* set st to highest possible value */
+    fill_systime_struct(&st, 30827, 12, 6, 31, 23, 59, 59, 999);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(1, r);
+
+    /* set st to value between min and max */
+    fill_systime_struct(&st, 1980, 1, 3, 23, 14, 34, 37, 465);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(1, r);
+    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    ok(r == GDT_VALID, "Expected %d, not %d(GDT_NONE) or %d(GDT_ERROR), got %ld\n", GDT_VALID, GDT_NONE, GDT_ERROR, r);
+    expect_systime(&st, &getSt);
+
+    /* set st to invalid value */
+    fill_systime_struct(&st, 0, 0, 7, 0, 24, 60, 60, 1000);
+
+    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect_unsuccess(0, r);
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_system_time_seq, "test_dtm_set_and_get_system_time", FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+static void test_datetime_control(void)
+{
+    HWND hWndDateTime;
+
+    hWndDateTime = create_datetime_control(DTS_SHOWNONE, 0);
+
+    ok(hWndDateTime != NULL, "Expected non NULL, got %p\n", hWndDateTime);
+    if(hWndDateTime!=NULL) {
+        test_dtm_set_format(hWndDateTime);
+        test_dtm_set_and_get_mccolor(hWndDateTime);
+        test_dtm_set_and_get_mcfont(hWndDateTime);
+        test_dtm_get_monthcal(hWndDateTime);
+        test_dtm_set_and_get_range(hWndDateTime);
+        test_dtm_set_range_swap_min_max(hWndDateTime);
+        test_dtm_set_and_get_system_time(hWndDateTime);
+    }
+    else {
+        skip("hWndDateTime is NULL\n");
+    }
+
+    DestroyWindow(hWndDateTime);
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, destroy_window_seq, "test_dtm_set_and_get_system_time", TRUE);
+}
+
+START_TEST(datetime)
+{
+    INITCOMMONCONTROLSEX icex;
+
+    icex.dwSize = sizeof(icex);
+    icex.dwICC = ICC_DATE_CLASSES;
+    InitCommonControlsEx(&icex);
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    test_datetime_control();
+}
index 4aa7b88..f1ca8f2 100644 (file)
 
 #include <stdarg.h>
 
-#include "windows.h"
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
 #include "commctrl.h"
 #include "objidl.h"
 
@@ -49,7 +52,7 @@ static PVOID   (WINAPI *pDPA_DeleteAllPtrs)(const HDPA);
 static PVOID   (WINAPI *pDPA_DeletePtr)(const HDPA,INT);
 static BOOL    (WINAPI *pDPA_Destroy)(const HDPA);
 static VOID    (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
-static VOID    (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
+static VOID    (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); 
 static INT     (WINAPI *pDPA_GetPtr)(const HDPA,INT);
 static INT     (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID);
 static BOOL    (WINAPI *pDPA_Grow)(HDPA,INT);
@@ -63,7 +66,7 @@ static BOOL    (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM);
 
 #define COMCTL32_GET_PROC(func, ord) \
   ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
-   : (trace( #func " not exported\n"), 0))
+   : (trace( #func " not exported\n"), 0)) 
 
 static BOOL InitFunctionPtrs(HMODULE hcomctl32)
 {
@@ -112,7 +115,7 @@ static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
 {
     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
     return p1;
-}
+}        
 
 static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
 {
@@ -123,7 +126,7 @@ static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM l
 static INT nEnum;
 
 static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
-{
+{   
     INT i;
 
     i = pDPA_GetPtrIndex(lp, pItem);
@@ -136,12 +139,12 @@ static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
 static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
 {
     HRESULT hRes;
-
+    
     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
     hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
-    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
     hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
-    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
     return S_OK;
 }
 
@@ -149,14 +152,14 @@ static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
 {
     HRESULT hRes;
     INT iOldPos;
-
+    
     iOldPos = pInfo->iPos;
     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
     hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
-    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
     ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
     hRes = IStream_Read(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
-    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
     return S_OK;
 }
 
@@ -171,23 +174,23 @@ static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
         if(!ulItem) break;
         dwOut = dwOut << 4 | (ulItem & 0xf);
     }
-
+    
     *pdwOut = dwOut;
 
     if(dwOut != dwIn)
     {
         pDPA_DeleteAllPtrs(dpa);
-
+        
         do
         {
             pDPA_InsertPtr(dpa, 0, (PVOID)(dwIn & 0xf));
             dwIn >>= 4;
         }
         while(dwIn);
-
+        
         return FALSE;
     }
-
+    
     return TRUE;
 }
 
@@ -200,16 +203,17 @@ static void test_dpa(void)
     PVOID p;
     DWORD dw, dw2, dw3;
     HRESULT hRes;
-
+    BOOL rc;
+    
     GetSystemInfo(&si);
     hHeap = HeapCreate(0, 1, 2);
-    ok(hHeap != NULL, "error=%ld\n", GetLastError());
+    ok(hHeap != NULL, "error=%d\n", GetLastError());
     dpa3 = pDPA_CreateEx(0, hHeap);
     ok(dpa3 != NULL, "\n");
     ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
-    todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
-       "ret=%d error=%ld\n", ret, GetLastError());
-
+    todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, 
+       "ret=%d error=%d\n", ret, GetLastError());
+        
     dpa = pDPA_Create(0);
     ok(dpa != NULL, "\n");
 
@@ -217,8 +221,9 @@ static void test_dpa(void)
     ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n");
     /* Fill the greated gap */
     ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n");
-    ok(CheckDPA(dpa, 0x56, &dw), "dw=0x%lx\n", dw);
-
+    rc=CheckDPA(dpa, 0x56, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+    
     /* Prepend item */
     ret = pDPA_InsertPtr(dpa, 1, (PVOID)1);
     ok(ret == 1, "ret=%d\n", ret);
@@ -228,11 +233,12 @@ static void test_dpa(void)
     /* Append item using out of bound index */
     ret = pDPA_InsertPtr(dpa, 5, (PVOID)2);
     ok(ret == 4, "ret=%d\n", ret);
-    /* Append item using DPA_APPEND */
+    /* Append item using DPA_APPEND */ 
     ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4);
     ok(ret == 5, "ret=%d\n", ret);
 
-    ok(CheckDPA(dpa, 0x516324, &dw), "dw=0x%lx\n", dw);
+    rc=CheckDPA(dpa, 0x516324, &dw);
+    ok(rc, "dw=0x%x\n", dw);
 
     for(i = 1; i <= 6; i++)
     {
@@ -245,24 +251,29 @@ static void test_dpa(void)
 
     /* Sort DPA */
     ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n");
-    ok(CheckDPA(dpa, 0x654321, &dw), "dw=0x%lx\n", dw);
-
+    rc=CheckDPA(dpa, 0x654321, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+    
     /* Clone into a new DPA */
     dpa2 = pDPA_Clone(dpa, NULL);
     ok(dpa2 != NULL, "\n");
     /* The old data should have been preserved */
-    ok(CheckDPA(dpa2, 0x654321, &dw2), "dw=0x%lx\n", dw2);
+    rc=CheckDPA(dpa2, 0x654321, &dw2);
+    ok(rc, "dw=0x%x\n", dw2);
     ok(pDPA_Sort(dpa, CB_CmpLT, 0xdeadbeef), "\n");
-
+    
     /* Test if the DPA itself was really copied */
-    ok(CheckDPA(dpa,  0x123456, &dw),  "dw=0x%lx\n",  dw );
-    ok(CheckDPA(dpa2, 0x654321, &dw2), "dw2=0x%lx\n", dw2);
+    rc=CheckDPA(dpa,  0x123456, &dw);
+    ok(rc, "dw=0x%x\n",  dw );
+    rc=CheckDPA(dpa2, 0x654321, &dw2);
+    ok(rc, "dw2=0x%x\n", dw2);
 
     /* Clone into an old DPA */
     p = NULL; SetLastError(ERROR_SUCCESS);
     p = pDPA_Clone(dpa, dpa3);
     ok(p == dpa3, "p=%p\n", p);
-    ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3);
+    rc=CheckDPA(dpa3, 0x123456, &dw3);
+    ok(rc, "dw3=0x%x\n", dw3);
 
     for(i = 1; i <= 6; i++)
     {
@@ -281,11 +292,11 @@ static void test_dpa(void)
         j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
         todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i);
     }
-
+    
     /* Try to get the index of a nonexistent item */
     i = pDPA_GetPtrIndex(dpa, (PVOID)7);
     ok(i == DPA_ERR, "i=%d\n", i);
-
+    
     /* Try to delete out of bound indexes */
     p = pDPA_DeletePtr(dpa, -1);
     ok(p == NULL, "p=%p\n", p);
@@ -295,10 +306,11 @@ static void test_dpa(void)
     /* Delete the third item */
     p = pDPA_DeletePtr(dpa, 2);
     ok(p == (PVOID)3, "p=%p\n", p);
-    ok(CheckDPA(dpa, 0x12456, &dw), "dw=0x%lx\n", dw);
+    rc=CheckDPA(dpa, 0x12456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
 
     /* Check where to re-insert the deleted item */
-    i = pDPA_Search(dpa, (PVOID)3, 0,
+    i = pDPA_Search(dpa, (PVOID)3, 0, 
                     CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTAFTER);
     ok(i == 2, "i=%d\n", i);
     /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
@@ -313,8 +325,9 @@ static void test_dpa(void)
     /* Re-insert the item */
     ret = pDPA_InsertPtr(dpa, 2, (PVOID)3);
     ok(ret == 2, "ret=%d i=%d\n", ret, 2);
-    ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw);
-
+    rc=CheckDPA(dpa, 0x123456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+    
     /* When doing a binary search while claiming reverse order all indexes
      * should be bogus */
     for(i = 0; i < 6; i++)
@@ -330,39 +343,49 @@ static void test_dpa(void)
         p = pDPA_DeletePtr(dpa, 1);
         p = pDPA_DeletePtr(dpa, 2);
         p = pDPA_DeletePtr(dpa, 3);
-        ok(CheckDPA(dpa, 0x135, &dw), "dw=0x%lx\n", dw);
-
+        rc=CheckDPA(dpa, 0x135, &dw);
+        ok(rc, "dw=0x%x\n", dw);
+    
         /* Delete all odd entries from dpa2 */
-        pDPA_Merge(dpa2, dpa, DPAM_DELETE,
+        pDPA_Merge(dpa2, dpa, DPAM_DELETE, 
                    CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef);
-        todo_wine ok(CheckDPA(dpa2, 0x246, &dw2), "dw=0x%lx\n", dw2);
-
+        todo_wine
+        {
+            rc=CheckDPA(dpa2, 0x246, &dw2);
+            ok(rc, "dw=0x%x\n", dw2);
+        }
+    
         /* Merge dpa3 into dpa2 and dpa */
-        pDPA_Merge(dpa, dpa3, DPAM_INSERT|DPAM_NOSORT,
+        pDPA_Merge(dpa, dpa3, DPAM_INSERT|DPAM_NOSORT, 
                    CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
-        pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT,
+        pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, 
                    CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
-
-        ok(CheckDPA(dpa,  0x123456, &dw ), "dw=0x%lx\n",  dw);
-        ok(CheckDPA(dpa2, 0x123456, &dw2), "dw2=0x%lx\n", dw2);
-        ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3);
+    
+        rc=CheckDPA(dpa,  0x123456, &dw);
+        ok(rc, "dw=0x%x\n",  dw);
+        rc=CheckDPA(dpa2, 0x123456, &dw2);
+        ok(rc, "dw2=0x%x\n", dw2);
+        rc=CheckDPA(dpa3, 0x123456, &dw3);
+        ok(rc, "dw3=0x%x\n", dw3);
     }
 
     if(pDPA_EnumCallback)
     {
         nEnum = 0;
         pDPA_EnumCallback(dpa2, CB_EnumFirstThree, (PVOID)dpa2);
-        ok(CheckDPA(dpa2, 0x777456, &dw2), "dw=0x%lx\n", dw2);
+        rc=CheckDPA(dpa2, 0x777456, &dw2);
+        ok(rc, "dw=0x%x\n", dw2);
         ok(nEnum == 3, "nEnum=%d\n", nEnum);
     }
-
+    
     /* Setting item with huge index should work */
     ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
     ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
     ok(ret == 0x12345, "ret=%d\n", ret);
-
+          
     pDPA_DeleteAllPtrs(dpa2);
-    ok(CheckDPA(dpa2, 0, &dw2), "dw2=0x%lx\n", dw2);
+    rc=CheckDPA(dpa2, 0, &dw2);
+    ok(rc, "dw2=0x%x\n", dw2);
     pDPA_Destroy(dpa2);
 
     if(pDPA_DestroyCallback)
@@ -388,31 +411,34 @@ static void test_dpa(void)
 
         dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
         hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
-        ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        ok(hRes == S_OK, "hRes=0x%x\n", hRes);
 
         hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
-        ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        ok(hRes == S_OK, "hRes=0x%x\n", hRes);
 
         hRes = pDPA_SaveStream(dpa, CB_Save, pStm, 0xdeadbeef);
-        todo_wine ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        todo_wine ok(hRes == S_OK, "hRes=0x%x\n", hRes);
         pDPA_Destroy(dpa);
-
+        
         hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
-        ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        ok(hRes == S_OK, "hRes=0x%x\n", hRes);
         hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, 0xdeadbeef);
-        todo_wine ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
-        todo_wine ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw);
-        pDPA_Destroy(dpa);
+        todo_wine
+        {
+            ok(hRes == S_OK, "hRes=0x%x\n", hRes);
+            rc=CheckDPA(dpa, 0x123456, &dw);
+            ok(rc, "dw=0x%x\n", dw);
+        }
 
         ret = IStream_Release(pStm);
         ok(!ret, "ret=%d\n", ret);
-
+       
         ret = IStorage_Release(pStg);
         ok(!ret, "ret=%d\n", ret);
 
         CoUninitialize();
     }
-    else ok(0, "hResult: %ld\n", hRes);
+    else ok(0, "hResult: %d\n", hRes);
 
 skip_stream_tests:
     pDPA_Destroy(dpa);
@@ -424,12 +450,6 @@ START_TEST(dpa)
 
     hcomctl32 = GetModuleHandleA("comctl32.dll");
 
-    if(!hcomctl32)
-    {
-        ok(0, "error=%ld\n", GetLastError());
-        return;
-    }
-
     if(InitFunctionPtrs(hcomctl32))
         test_dpa();
     else
index 3d72e19..e80944f 100644 (file)
@@ -1,6 +1,7 @@
 /* Unit test suite for header control.
  *
  * Copyright 2005 Vijay Kiran Kamuju
+ * Copyright 2007 Shanren Zhou
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,6 +24,7 @@
 #include <assert.h>
 
 #include "wine/test.h"
+#include "msg.h"
 
 typedef struct tagEXPECTEDNOTIFY
 {
@@ -31,16 +33,186 @@ typedef struct tagEXPECTEDNOTIFY
     HDITEMA hdItem;
 } EXPECTEDNOTIFY;
 
-EXPECTEDNOTIFY expectedNotify[10];
-INT nExpectedNotify = 0;
-INT nReceivedNotify = 0;
-INT unexpectedNotify[10];
-INT nUnexpectedNotify = 0;
+typedef LRESULT (*CUSTOMDRAWPROC)(int n, NMCUSTOMDRAW *nm);
+
+static CUSTOMDRAWPROC g_CustomDrawProc;
+static int g_CustomDrawCount;
+static DRAWITEMSTRUCT g_DrawItem;
+static BOOL g_DrawItemReceived;
+
+static EXPECTEDNOTIFY expectedNotify[10];
+static INT nExpectedNotify = 0;
+static INT nReceivedNotify = 0;
+static INT unexpectedNotify[10];
+static INT nUnexpectedNotify = 0;
 
 static HWND hHeaderParentWnd;
 static HWND hWndHeader;
 #define MAX_CHARS 100
 
+#define compare(val, exp, fmt)  ok((val) == (exp), #val " value: " fmt ", expected: " fmt "\n", (val), (exp))
+
+#define expect(expected, got) ok(expected == got, "expected %d, got %d\n", expected,got)
+
+#define NUM_MSG_SEQUENCES    2
+#define PARENT_SEQ_INDEX     0
+#define HEADER_SEQ_INDEX     1
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message create_parent_wnd_seq[] = {
+    { WM_GETMINMAXINFO, sent },
+    { WM_NCCREATE, sent },
+    { WM_NCCALCSIZE, sent|wparam, 0 },
+    { WM_CREATE, sent },
+    { 0 }
+};
+
+static const struct message add_header_to_parent_seq_interactive[] = {
+    { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
+    { WM_QUERYUISTATE, sent },
+    { WM_PARENTNOTIFY, sent|wparam, 1 },
+    { WM_SHOWWINDOW, sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_IME_SETCONTEXT, sent|defwinproc|wparam, 1 },
+    { WM_IME_NOTIFY, sent|defwinproc|wparam, 2 },
+    { WM_SETFOCUS, sent|defwinproc|wparam, 0 },
+    { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
+    { WM_SIZE, sent|wparam, 0 },
+    { WM_MOVE, sent|wparam, 0 },
+    { 0 }
+};
+
+static const struct message add_header_to_parent_seq[] = {
+    { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
+    { WM_QUERYUISTATE, sent },
+    { WM_PARENTNOTIFY, sent },
+    { 0 }
+};
+
+static const struct message insertItem_seq[] = {
+    { HDM_INSERTITEM, sent|wparam, 0 },
+    { HDM_INSERTITEM, sent|wparam, 1 },
+    { HDM_INSERTITEM, sent|wparam, 2 },
+    { HDM_INSERTITEM, sent|wparam, 3 },
+    { 0 }
+};
+
+static const struct message getItem_seq[] = {
+    { HDM_GETITEM, sent|wparam, 3 },
+    { HDM_GETITEM, sent|wparam, 0 },
+    { 0 }
+};
+
+
+static const struct message deleteItem_getItemCount_seq[] = {
+    { HDM_DELETEITEM, sent|wparam, 3 },
+    { HDM_GETITEMCOUNT, sent },
+    { HDM_DELETEITEM, sent|wparam, 3 },
+    { HDM_GETITEMCOUNT, sent },
+    { HDM_DELETEITEM, sent|wparam, 2 },
+    { HDM_GETITEMCOUNT, sent },
+    { 0 }
+};
+
+static const struct message orderArray_seq[] = {
+    { HDM_GETITEMCOUNT, sent },
+    { HDM_SETORDERARRAY, sent|wparam, 2 },
+    { HDM_GETORDERARRAY, sent|wparam, 2 },
+    { 0 }
+};
+
+static const struct message setItem_seq[] = {
+    { HDM_SETITEM, sent|wparam, 0 },
+    { HDM_SETITEM, sent|wparam, 1 },
+    { 0 }
+};
+
+static const struct message getItemRect_seq[] = {
+    { HDM_GETITEMRECT, sent|wparam, 1 },
+    { HDM_GETITEMRECT, sent|wparam, 0 },
+    { HDM_GETITEMRECT, sent|wparam, 10 },
+    { 0 }
+};
+
+static const struct message layout_seq[] = {
+    { HDM_LAYOUT, sent },
+    { 0 }
+};
+
+static const struct message orderToIndex_seq[] = {
+    { HDM_ORDERTOINDEX, sent|wparam, 1 },
+    { 0 }
+};
+
+static const struct message hittest_seq[] = {
+    { HDM_HITTEST, sent },
+    { HDM_HITTEST, sent },
+    { HDM_HITTEST, sent },
+    { 0 }
+};
+
+static const struct message setHotDivider_seq_interactive[] = {
+    { HDM_SETHOTDIVIDER, sent|wparam, TRUE },
+    { WM_PAINT, sent|defwinproc},
+    { WM_NCPAINT, sent|defwinproc},
+    { WM_ERASEBKGND, sent|defwinproc},
+    { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 100 },
+    { WM_PAINT, sent|defwinproc},
+    { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 1},
+    { WM_PAINT, sent|defwinproc},
+    { 0 }
+};
+
+static const struct message setHotDivider_seq_noninteractive[] = {
+    { HDM_SETHOTDIVIDER, sent|wparam, TRUE },
+    { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 100 },
+    { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 1},
+    { 0 }
+};
+
+static const struct message imageMessages_seq[] = {
+    { HDM_SETIMAGELIST, sent },
+    { HDM_GETIMAGELIST, sent },
+    { HDM_CREATEDRAGIMAGE, sent },
+    { 0 }
+};
+
+static const struct message filterMessages_seq_interactive[] = {
+    { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 },
+    { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 },
+    { HDM_EDITFILTER,  sent|wparam|lparam, 1, 0 },
+    { WM_PARENTNOTIFY, sent|wparam|defwinproc, WM_CREATE },
+    { WM_CTLCOLOREDIT, sent|defwinproc },
+    { WM_COMMAND, sent|defwinproc },
+    { 0 }
+};
+
+static const struct message filterMessages_seq_noninteractive[] = {
+    { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 },
+    { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 },
+    { HDM_EDITFILTER,  sent|wparam|lparam, 1, 0 },
+    { WM_PARENTNOTIFY, sent|wparam|defwinproc, WM_CREATE },
+    { WM_COMMAND, sent|defwinproc },
+    { 0 }
+};
+
+static const struct message unicodeformatMessages_seq[] = {
+    { HDM_SETUNICODEFORMAT, sent|wparam, TRUE },
+    { HDM_GETUNICODEFORMAT, sent },
+    { 0 }
+};
+
+static const struct message bitmapmarginMessages_seq[] = {
+    { HDM_GETBITMAPMARGIN, sent },
+    { 0 }
+};
+
+
 static void expect_notify(INT iCode, BOOL fUnicode, HDITEMA *lpItem)
 {
     assert(nExpectedNotify < 10);
@@ -64,22 +236,22 @@ static BOOL notifies_received(void)
     return fRet;
 }
 
-static LONG addItem(HWND hdex, int idx, LPCSTR text)
+static LONG addItem(HWND hdex, int idx, LPSTR text)
 {
     HDITEMA hdItem;
     hdItem.mask       = HDI_TEXT | HDI_WIDTH;
     hdItem.cxy        = 100;
-    hdItem.pszText    = (LPSTR)text;
+    hdItem.pszText    = text;
     hdItem.cchTextMax = 0;
     return (LONG)SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)idx, (LPARAM)&hdItem);
 }
 
-static LONG setItem(HWND hdex, int idx, LPCSTR text, BOOL fCheckNotifies)
+static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies)
 {
     LONG ret;
     HDITEMA hdexItem;
     hdexItem.mask       = HDI_TEXT;
-    hdexItem.pszText    = (LPSTR)text;
+    hdexItem.pszText    = text;
     hdexItem.cchTextMax = 0;
     if (fCheckNotifies)
     {
@@ -92,18 +264,18 @@ static LONG setItem(HWND hdex, int idx, LPCSTR text, BOOL fCheckNotifies)
     return ret;
 }
 
-static LONG setItemUnicodeNotify(HWND hdex, int idx, LPCSTR text, LPCWSTR wText)
+static LONG setItemUnicodeNotify(HWND hdex, int idx, LPSTR text, LPWSTR wText)
 {
     LONG ret;
     HDITEMA hdexItem;
     HDITEMW hdexNotify;
     hdexItem.mask       = HDI_TEXT;
-    hdexItem.pszText    = (LPSTR)text;
+    hdexItem.pszText    = text;
     hdexItem.cchTextMax = 0;
-
+    
     hdexNotify.mask    = HDI_TEXT;
-    hdexNotify.pszText = (LPWSTR)wText;
-
+    hdexNotify.pszText = wText;
+    
     expect_notify(HDN_ITEMCHANGINGW, TRUE, (HDITEMA*)&hdexNotify);
     expect_notify(HDN_ITEMCHANGEDW, TRUE, (HDITEMA*)&hdexNotify);
     ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem);
@@ -136,7 +308,7 @@ static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA
     ZeroMemory(phdiRead, sizeof(HDITEMA));
     phdiRead->mask = maskRead;
     ok(SendMessage(hdex, HDM_GETITEMA, (WPARAM)0, (LPARAM)phdiRead)!=0, "Getting item data failed\n");
-    ok(SendMessage(hdex, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0)!=0, "Deleteing item failed\n");
+    ok(SendMessage(hdex, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0)!=0, "Deleting item failed\n");
 }
 
 static HWND create_header_control (void)
@@ -159,7 +331,7 @@ static HWND create_header_control (void)
     hlayout.prc = &rectwin;
     hlayout.pwpos = &winpos;
     SendMessageA(handle,HDM_LAYOUT,0,(LPARAM) &hlayout);
-    SetWindowPos(handle, winpos.hwndInsertAfter, winpos.x, winpos.y,
+    SetWindowPos(handle, winpos.hwndInsertAfter, winpos.x, winpos.y, 
                  winpos.cx, winpos.cy, 0);
 
     return handle;
@@ -198,22 +370,173 @@ static void compare_items(INT iCode, HDITEMA *hdi1, HDITEMA *hdi2, BOOL fUnicode
     }
 }
 
-static const char *str_items[] =
-    {"First Item", "Second Item", "Third Item", "Fourth Item", "Replace Item", "Out Of Range Item"};
+static char pszFirstItem[]      = "First Item";
+static char pszSecondItem[]     = "Second Item";
+static char pszThirdItem[]      = "Third Item";
+static char pszFourthItem[]     = "Fourth Item";
+static char pszReplaceItem[]    = "Replace Item";
+static char pszOutOfRangeItem[] = "Out Of Range Item";
 
-static const char pszUniTestA[] = "TST";
-static const WCHAR pszUniTestW[] = {'T','S','T',0};
+static char *str_items[] =
+    {pszFirstItem, pszSecondItem, pszThirdItem, pszFourthItem, pszReplaceItem, pszOutOfRangeItem};
+    
+static char pszUniTestA[]  = "TST";
+static WCHAR pszUniTestW[] = {'T','S','T',0};
 
 
 #define TEST_GET_ITEM(i,c)\
 {   res = getItem(hWndHeader, i, buffer);\
-    ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%ld)\n", i, res);\
+    ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%d)\n", i, res);\
     ok(strcmp(str_items[c], buffer) == 0, "Getting item[%d] returned \"%s\" expecting \"%s\"\n", i, buffer, str_items[c]);\
 }
 
 #define TEST_GET_ITEMCOUNT(i)\
 {   res = getItemCount(hWndHeader);\
-    ok(res == i, "Got Item Count as %ld\n", res);\
+    ok(res == i, "Got Item Count as %d\n", res);\
+}
+
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, HEADER_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+   }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL register_parent_wnd_class(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Header test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND create_custom_parent_window(void)
+{
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindowExA(0, "Header test parent class", "Header Message Sequence Testing",
+                           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
+                           672+2*GetSystemMetrics(SM_CXSIZEFRAME),
+                           226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
+                           NULL, NULL, GetModuleHandleA(NULL), 0);
+}
+
+static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
+{
+    struct subclass_info *info;
+    HWND childHandle;
+    HDLAYOUT hlayout;
+    RECT rectwin;
+    WINDOWPOS winpos;
+    int retVal;
+    int loopcnt;
+    static char firstHeaderItem[] = "Name";
+    static char secondHeaderItem[] = "Size";
+    static char *items[] = {secondHeaderItem, firstHeaderItem};
+    HDITEM hdItem;
+    hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
+    hdItem.fmt = HDF_LEFT;
+    hdItem.cxy = 80;
+    hdItem.cchTextMax = 260;
+
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+         return NULL;
+
+    childHandle = CreateWindowEx(0, WC_HEADER, NULL,
+                           WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
+                           0, 0, 0, 0,
+                           hParent, NULL, NULL, NULL);
+    assert(childHandle);
+    if (preloadHeaderItems)
+    {
+         for ( loopcnt = 0 ; loopcnt < 2 ; loopcnt++ )
+         {
+             hdItem.pszText = items[loopcnt];
+             retVal = SendMessage(childHandle, HDM_INSERTITEM, loopcnt, (LPARAM) &hdItem);
+             ok(retVal == loopcnt, "Adding item %d failed with return value %d\n", ( loopcnt + 1 ), retVal);
+          }
+    }
+
+    if (winetest_interactive)
+       ShowWindow (hParent, SW_SHOW);
+
+    GetClientRect(hParent,&rectwin);
+    hlayout.prc = &rectwin;
+    hlayout.pwpos = &winpos;
+    SendMessageA(childHandle,HDM_LAYOUT,0,(LPARAM) &hlayout);
+    SetWindowPos(childHandle, winpos.hwndInsertAfter, winpos.x, winpos.y,
+                 winpos.cx, winpos.cy, 0);
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(childHandle, GWLP_WNDPROC,
+                                               (LONG_PTR)header_subclass_proc);
+    SetWindowLongPtrA(childHandle, GWLP_USERDATA, (LONG_PTR)info);
+    return childHandle;
 }
 
 static void check_auto_format(void)
@@ -275,7 +598,7 @@ static void check_auto_fields(void)
     HDITEMA hdiCreate;
     HDITEMA hdiRead;
     static CHAR text[] = "Test";
-    LRESULT res;
+    LONG res;
 
     /* Windows stores the format, width, lparam even if they are not in the item's mask */
     ZeroMemory(&hdiCreate, sizeof(HDITEMA));
@@ -390,25 +713,25 @@ static void test_header_control (void)
     {
         TEST_GET_ITEMCOUNT(3-i);
         res = addItem(hWndHeader, 0, str_items[i]);
-        ok(res == 0, "Adding simple item failed (%ld)\n", res);
+        ok(res == 0, "Adding simple item failed (%d)\n", res);
     }
 
     TEST_GET_ITEMCOUNT(4);
     res = addItem(hWndHeader, 99, str_items[i+1]);
-    ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res);
+    ok(res != -1, "Adding Out of Range item should fail with -1 got (%d)\n", res);
     TEST_GET_ITEMCOUNT(5);
     res = addItem(hWndHeader, 5, str_items[i+1]);
-    ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res);
+    ok(res != -1, "Adding Out of Range item should fail with -1 got (%d)\n", res);
     TEST_GET_ITEMCOUNT(6);
 
     for (i = 0; i < 4; i++) { TEST_GET_ITEM(i,i); TEST_GET_ITEMCOUNT(6); }
 
     res=getItem(hWndHeader, 99, buffer);
-    ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer);
+    ok(res == 0, "Getting Out of Range item should fail with 0 (%d), got %s\n", res,buffer);
     res=getItem(hWndHeader, 5, buffer);
-    ok(res == 1, "Getting Out of Range item should fail with 1 (%ld), got %s\n", res,buffer);
+    ok(res == 1, "Getting Out of Range item should fail with 1 (%d), got %s\n", res,buffer);
     res=getItem(hWndHeader, -2, buffer);
-    ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer);
+    ok(res == 0, "Getting Out of Range item should fail with 0 (%d), got %s\n", res,buffer);
 
     if (winetest_interactive)
     {
@@ -418,26 +741,26 @@ static void test_header_control (void)
 
     TEST_GET_ITEMCOUNT(6);
     res=setItem(hWndHeader, 99, str_items[5], FALSE);
-    ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res);
+    ok(res == 0, "Setting Out of Range item should fail with 0 (%d)\n", res);
     res=setItem(hWndHeader, 5, str_items[5], TRUE);
-    ok(res == 1, "Setting Out of Range item should fail with 1 (%ld)\n", res);
+    ok(res == 1, "Setting Out of Range item should fail with 1 (%d)\n", res);
     res=setItem(hWndHeader, -2, str_items[5], FALSE);
-    ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res);
+    ok(res == 0, "Setting Out of Range item should fail with 0 (%d)\n", res);
     TEST_GET_ITEMCOUNT(6);
 
     for (i = 0; i < 4; i++)
     {
         res = setItem(hWndHeader, i, str_items[4], TRUE);
-        ok(res != 0, "Setting %d item failed (%ld)\n", i+1, res);
+        ok(res != 0, "Setting %d item failed (%d)\n", i+1, res);
         TEST_GET_ITEM(i, 4);
         TEST_GET_ITEMCOUNT(6);
     }
-
+    
     SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, 0);
     setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW);
     SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, (LPARAM)NF_REQUERY);
     setItem(hWndHeader, 3, str_items[4], TRUE);
-
+    
     dont_expect_notify(HDN_GETDISPINFOA);
     dont_expect_notify(HDN_GETDISPINFOW);
     addItem(hWndHeader, 0, LPSTR_TEXTCALLBACKA);
@@ -457,30 +780,652 @@ static void test_header_control (void)
     TEST_GET_ITEMCOUNT(6);
 
     res = delItem(hWndHeader, 5);
-    ok(res == 1, "Deleting Out of Range item should fail with 1 (%ld)\n", res);
+    ok(res == 1, "Deleting Out of Range item should fail with 1 (%d)\n", res);
     res = delItem(hWndHeader, -2);
-    ok(res == 0, "Deleting Out of Range item should fail with 0 (%ld)\n", res);
+    ok(res == 0, "Deleting Out of Range item should fail with 0 (%d)\n", res);
     TEST_GET_ITEMCOUNT(5);
 
     res = delItem(hWndHeader, 3);
-    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res != 0, "Deleting using out of range index failed (%d)\n", res);
     TEST_GET_ITEMCOUNT(4);
     res = delItem(hWndHeader, 0);
-    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res != 0, "Deleting using out of range index failed (%d)\n", res);
     TEST_GET_ITEMCOUNT(3);
     res = delItem(hWndHeader, 0);
-    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res != 0, "Deleting using out of range index failed (%d)\n", res);
     TEST_GET_ITEMCOUNT(2);
     res = delItem(hWndHeader, 0);
-    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    ok(res != 0, "Deleting using out of range index failed (%d)\n", res);
     TEST_GET_ITEMCOUNT(1);
 
     DestroyWindow(hWndHeader);
 }
 
+static void test_hdm_getitemrect(HWND hParent)
+{
+
+    HWND hChild;
+    RECT rect;
+    int retVal;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    retVal = SendMessage(hChild, HDM_GETITEMRECT, 1, (LPARAM) &rect);
+    ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal);
+    /* check bounding rectangle information of 2nd header item */
+    expect(80, rect.left);
+    expect(0, rect.top);
+    expect(160, rect.right);
+    todo_wine
+    {
+      expect(18, rect.bottom);
+    }
+    retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect);
+
+    ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal);
+    /* check bounding rectangle information of 1st header item */
+    expect(0, rect.left);
+    expect(0, rect.top);
+
+    expect(80, rect.right);
+    todo_wine
+    {
+      expect(18, rect.bottom);
+    }
+    retVal = SendMessage(hChild, HDM_GETITEMRECT, 10, (LPARAM) &rect);
+    ok(retVal == 0, "Getting rect of nonexistent item should return 0, got %d\n", retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, getItemRect_seq, "getItemRect sequence testing", FALSE);
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_layout(HWND hParent)
+{
+    HWND hChild;
+    int retVal;
+    RECT rect;
+    HDLAYOUT hdLayout;
+    WINDOWPOS windowPos;
+    hdLayout.prc = &rect;
+    hdLayout.pwpos = &windowPos;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    retVal = SendMessage(hChild, HDM_LAYOUT, 0, (LPARAM) &hdLayout);
+    expect(TRUE, retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, layout_seq, "layout sequence testing", FALSE);
+
+    DestroyWindow(hChild);
+}
 
-LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+static void test_hdm_ordertoindex(HWND hParent)
 {
+    HWND hChild;
+    int retVal;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    retVal = SendMessage(hChild, HDM_ORDERTOINDEX, 1, 0);
+    expect(1, retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, orderToIndex_seq, "orderToIndex sequence testing", FALSE);
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_hittest(HWND hParent)
+{
+    HWND hChild;
+    int retVal;
+    POINT pt;
+    HDHITTESTINFO hdHitTestInfo;
+    const int firstItemRightBoundary = 80;
+    const int secondItemRightBoundary = 160;
+    const int bottomBoundary = 18;
+
+    pt.x = firstItemRightBoundary - 1;
+    pt.y = bottomBoundary - 1;
+    hdHitTestInfo.pt = pt;
+
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
+    todo_wine
+    {
+      expect(0, retVal);
+      expect(0, hdHitTestInfo.iItem);
+    }
+
+    pt.x = secondItemRightBoundary - 1;
+    pt.y = bottomBoundary - 1;
+    hdHitTestInfo.pt = pt;
+    retVal = SendMessage(hChild, HDM_HITTEST, 1, (LPARAM) &hdHitTestInfo);
+    todo_wine
+    {
+      expect(1, retVal);
+    }
+    expect(1, hdHitTestInfo.iItem);
+
+    pt.x = secondItemRightBoundary;
+    pt.y = bottomBoundary + 1;
+    hdHitTestInfo.pt = pt;
+    todo_wine
+    {
+     retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
+     expect(-1, retVal);
+    }
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, hittest_seq, "hittest sequence testing", FALSE);
+
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_sethotdivider(HWND hParent)
+{
+    HWND hChild;
+    int retVal;
+    /*  low word: x coordinate = 5
+     *  high word:  y coordinate = 5
+     */
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    todo_wine
+    {
+        retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, (LPARAM) 0X00050005);
+        expect(0, retVal);
+    }
+    retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 100);
+    expect(100, retVal);
+    retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 1);
+    expect(1, retVal);
+    if (winetest_interactive)
+       ok_sequence(sequences, HEADER_SEQ_INDEX, setHotDivider_seq_interactive,
+                   "setHotDivider sequence testing", TRUE);
+    else
+       ok_sequence(sequences, HEADER_SEQ_INDEX, setHotDivider_seq_noninteractive,
+                   "setHotDivider sequence testing", FALSE);
+
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_imageMessages(HWND hParent)
+{
+    HIMAGELIST hImageList = ImageList_Create (4, 4, 0, 1, 0);
+    HIMAGELIST hImageListRetVal;
+    HWND hChild;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList);
+    ok(hImageListRetVal == NULL, "Expected NULL, got %d\n", (int) hImageListRetVal);
+
+    hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0);
+    ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal);
+
+    hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0);
+    ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE);
+
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_filterMessages(HWND hParent)
+{
+    HWND hChild;
+    int retVal;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    assert(hChild);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    todo_wine
+    {
+     /* msdn incorrecly states that return value
+      * is the index of the filter control being
+      * modified. The sendMessage here should
+      * return previous filter timeout value
+     */
+        retVal = SendMessage(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, 100);
+        expect(1000, retVal);
+        retVal = SendMessage(hChild, HDM_CLEARFILTER, 0, 1);
+        expect(1, retVal);
+        retVal = SendMessage(hChild, HDM_EDITFILTER, 1, 0);
+        expect(1, retVal);
+     }
+    if (winetest_interactive)
+         ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_interactive,
+                     "filterMessages sequence testing", TRUE);
+    else
+         ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_noninteractive,
+                     "filterMessages sequence testing", TRUE);
+    DestroyWindow(hChild);
+
+}
+
+static void test_hdm_unicodeformatMessages(HWND hParent)
+{
+    HWND hChild;
+    int retVal;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    retVal = SendMessage(hChild, HDM_SETUNICODEFORMAT, TRUE, 0);
+    expect(0, retVal);
+    retVal = SendMessage(hChild, HDM_GETUNICODEFORMAT, 0, 0);
+    expect(1, retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, unicodeformatMessages_seq,
+                     "unicodeformatMessages sequence testing", FALSE);
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_bitmapmarginMessages(HWND hParent)
+{
+    HWND hChild;
+    int retVal;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                    "adder header control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    retVal = SendMessage(hChild, HDM_GETBITMAPMARGIN, 0, 0);
+    expect(6, retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, bitmapmarginMessages_seq,
+                      "bitmapmarginMessages sequence testing", FALSE);
+    DestroyWindow(hChild);
+}
+
+static void test_hdm_index_messages(HWND hParent)
+{
+
+    HWND hChild;
+    int retVal;
+    int loopcnt;
+    int strcmpResult;
+    int iSize;
+    static const int lpiarray[2] = {1, 0};
+    static int lpiarrayReceived[2];
+    static char firstHeaderItem[] = "Name";
+    static char secondHeaderItem[] = "Size";
+    static char thirdHeaderItem[] = "Type";
+    static char fourthHeaderItem[] = "Date Modified";
+    static char *items[] = {firstHeaderItem, secondHeaderItem, thirdHeaderItem, fourthHeaderItem};
+    HDITEM hdItem;
+    hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
+    hdItem.fmt = HDF_LEFT;
+    hdItem.cxy = 80;
+    hdItem.cchTextMax = 260;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hChild = create_custom_header_control(hParent, FALSE);
+    if (winetest_interactive)
+         ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq_interactive,
+                                              "adder header control to parent", TRUE);
+    else
+         ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
+                                     "adder header control to parent", TRUE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    for ( loopcnt = 0 ; loopcnt < 4 ; loopcnt++ )
+    {
+      hdItem.pszText = items[loopcnt];
+      retVal = SendMessage(hChild, HDM_INSERTITEM, loopcnt, (LPARAM) &hdItem);
+      ok(retVal == loopcnt, "Adding item %d failed with return value %d\n", ( loopcnt + 1 ), retVal);
+    }
+    ok_sequence(sequences, HEADER_SEQ_INDEX, insertItem_seq, "insertItem sequence testing", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    retVal = SendMessage(hChild, HDM_DELETEITEM, 3, (LPARAM) &hdItem);
+    ok(retVal == TRUE, "Deleting item 3 should return TRUE, got %d\n", retVal);
+    retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem);
+    ok(retVal == 3, "Getting item count should return 3, got %d\n", retVal);
+
+    retVal = SendMessage(hChild, HDM_DELETEITEM, 3, (LPARAM) &hdItem);
+    ok(retVal == FALSE, "Deleting already-deleted item should return FALSE, got %d\n", retVal);
+    retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem);
+    ok(retVal == 3, "Getting item count should return 3, got %d\n", retVal);
+
+    retVal = SendMessage(hChild, HDM_DELETEITEM, 2, (LPARAM) &hdItem);
+    ok(retVal == TRUE, "Deleting item 2 should return TRUE, got %d\n", retVal);
+    retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem);
+    ok(retVal == 2, "Getting item count should return 2, got %d\n", retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, deleteItem_getItemCount_seq,
+                         "deleteItem_getItemCount sequence testing", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    retVal = SendMessage(hChild, HDM_GETITEM, 3, (LPARAM) &hdItem);
+    ok(retVal == FALSE, "Getting already-deleted item should return FALSE, got %d\n", retVal);
+
+    retVal = SendMessage(hChild, HDM_GETITEM, 0, (LPARAM) &hdItem);
+    ok(retVal == TRUE, "Getting the 1st header item should return TRUE, got %d\n", retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, getItem_seq, "getItem sequence testing", FALSE);
+
+    /* check if the item is the right one */
+    strcmpResult =  strcmp(hdItem.pszText, firstHeaderItem);
+    expect(0, strcmpResult);
+    expect(80, hdItem.cxy);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem);
+    retVal = SendMessage(hChild, HDM_SETORDERARRAY, (WPARAM) iSize , (LPARAM) (LPINT) lpiarray );
+    ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal);
+
+    retVal = SendMessage(hChild, HDM_GETORDERARRAY, (WPARAM) iSize, (LPARAM) (LPINT) lpiarrayReceived );
+    ok(retVal == TRUE, "Getting header items order should return TRUE, got %d\n", retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, orderArray_seq, "set_get_orderArray sequence testing", FALSE);
+
+    /* check if the array order is set correctly and the size of the array is corret. */
+    expect(2, iSize);
+    expect(lpiarray[0], lpiarrayReceived[0]);
+    expect(lpiarray[1], lpiarrayReceived[1]);
+
+    hdItem.mask = HDI_FORMAT;
+    hdItem.fmt = HDF_CENTER | HDF_STRING;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    retVal = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM) &hdItem);
+    ok(retVal == TRUE, "Aligning 1st header item to center should return TRUE, got %d\n", retVal);
+    hdItem.fmt = HDF_RIGHT | HDF_STRING;
+    retVal = SendMessage(hChild, HDM_SETITEM, 1, (LPARAM) &hdItem);
+    ok(retVal == TRUE, "Aligning 2nd header item to right should return TRUE, got %d\n", retVal);
+
+    ok_sequence(sequences, HEADER_SEQ_INDEX, setItem_seq, "setItem sequence testing", FALSE);
+    DestroyWindow(hChild);
+}
+
+#define TEST_NMCUSTOMDRAW(draw_stage, item_spec, lparam, _left, _top, _right, _bottom) \
+    ok(nm->dwDrawStage == draw_stage, "Invalid dwDrawStage %d vs %d\n", draw_stage, nm->dwDrawStage); \
+    if (item_spec != -1) \
+        ok(nm->dwItemSpec == item_spec, "Invalid dwItemSpec %d vs %ld\n", item_spec, nm->dwItemSpec); \
+    ok(nm->lItemlParam == lparam, "Invalid lItemlParam %d vs %ld\n", lparam, nm->lItemlParam); \
+    ok(nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right, \
+        "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", _left, _top, _right, _bottom, \
+        nm->rc.left, nm->rc.top, nm->rc.right, nm->rc.bottom);
+
+static LRESULT customdraw_1(int n, NMCUSTOMDRAW *nm)
+{
+    if (nm == NULL) {  /* test ended */
+        ok(n==1, "NM_CUSTOMDRAW messages: %d, expected: 1\n", n);
+        return 0;
+    }
+
+    switch (n)
+    {
+    case 0:
+        /* don't test dwItemSpec - it's 0 no comctl5 but 1308756 on comctl6 */
+        TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
+        return 0;
+    }
+
+    ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
+    return -1;
+}
+
+static LRESULT customdraw_2(int n, NMCUSTOMDRAW *nm)
+{
+    if (nm == NULL) {  /* test ended */
+        ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n);
+        return 0;
+    }
+
+    switch (n)
+    {
+    case 0:
+        TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
+        return CDRF_NOTIFYITEMDRAW;
+    case 1:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18);
+        return 0;
+    case 2:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18);
+        return 0;
+    case 3:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18);
+        return 0;
+    }
+
+    ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
+    return 0;
+}
+
+static LRESULT customdraw_3(int n, NMCUSTOMDRAW *nm)
+{
+    if (nm == NULL) {  /* test ended */
+        ok(n==5, "NM_CUSTOMDRAW messages: %d, expected: 5\n", n);
+        return 0;
+    }
+
+    switch (n)
+    {
+    case 0:
+        TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
+        return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTERASE|CDRF_NOTIFYPOSTPAINT|CDRF_SKIPDEFAULT;
+    case 1:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18);
+        return 0;
+    case 2:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18);
+        return 0;
+    case 3:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18);
+        return 0;
+    case 4:
+        TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18);
+        return 0;
+    }
+
+    ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
+    return 0;
+}
+
+
+static LRESULT customdraw_4(int n, NMCUSTOMDRAW *nm)
+{
+    if (nm == NULL) {  /* test ended */
+        ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n);
+        return 0;
+    }
+
+    switch (n)
+    {
+    case 0:
+        TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18);
+        return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
+    case 1:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18);
+        return 0;
+    case 2:
+        TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18);
+        return 0;
+    case 3:
+        TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18);
+        return 0;
+    }
+
+    ok(FALSE, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n, nm->dwDrawStage);
+    return 0;
+}
+
+static void run_customdraw_scenario(CUSTOMDRAWPROC proc)
+{
+    g_CustomDrawProc = proc;
+    g_CustomDrawCount = 0;
+    InvalidateRect(hWndHeader, NULL, TRUE);
+    UpdateWindow(hWndHeader);
+    proc(g_CustomDrawCount, NULL);
+    g_CustomDrawProc = NULL;
+}
+
+static void test_customdraw(void)
+{
+    int i;
+    HDITEM item;
+    RECT rect;
+    CHAR name[] = "Test";
+    hWndHeader = create_header_control();
+    GetClientRect(hWndHeader, &rect);
+    ok(rect.right - rect.left == 670 && rect.bottom - rect.top == 18,
+        "Tests will fail as header size is %dx%d instead of 670x18\n",
+        rect.right - rect.left, rect.bottom - rect.top);
+
+    for (i = 0; i < 3; i++)
+    {
+        ZeroMemory(&item, sizeof(item));
+        item.mask = HDI_TEXT|HDI_WIDTH;
+        item.cxy = 50*(i+1);
+        item.pszText = name;
+        item.lParam = i*5;
+        SendMessage(hWndHeader, HDM_INSERTITEM, i, (LPARAM)&item);
+    }
+
+    run_customdraw_scenario(customdraw_1);
+    run_customdraw_scenario(customdraw_2);
+    run_customdraw_scenario(customdraw_3);
+
+    ZeroMemory(&item, sizeof(item));
+    item.mask = HDI_FORMAT;
+    item.fmt = HDF_OWNERDRAW;
+    SendMessage(hWndHeader, HDM_SETITEM, 1, (LPARAM)&item);
+    g_DrawItem.CtlID = 0;
+    g_DrawItem.CtlType = ODT_HEADER;
+    g_DrawItem.hwndItem = hWndHeader;
+    g_DrawItem.itemID = 1;
+    g_DrawItem.itemState = 0;
+    SendMessage(hWndHeader, HDM_GETITEMRECT, 1, (LPARAM)&g_DrawItem.rcItem);
+    run_customdraw_scenario(customdraw_4);
+    ok(g_DrawItemReceived, "WM_DRAWITEM not received\n");
+    DestroyWindow(hWndHeader);
+    hWndHeader = NULL;
+    g_DrawItem.CtlType = 0;
+    g_DrawItemReceived = FALSE;
+}
+
+static void check_order(const int expected_id[], const int expected_order[],
+                        int count, const char *type)
+{
+    int i;
+    HDITEMA hdi;
+
+    ok(getItemCount(hWndHeader) == count, "Invalid item count in order tests\n");
+    for (i = 0; i < count; i++)
+    {
+        hdi.mask = HDI_LPARAM|HDI_ORDER;
+        SendMessage(hWndHeader, HDM_GETITEMA, i, (LPARAM)&hdi);
+        ok(hdi.lParam == expected_id[i],
+            "Invalid item ids after '%s'- item %d has lParam %d\n", type, i, (int)hdi.lParam);
+        ok(hdi.iOrder == expected_order[i],
+            "Invalid item order after '%s'- item %d has iOrder %d\n", type, i, hdi.iOrder);
+    }
+}
+
+static void test_header_order (void)
+{
+    const int rand1[] = {0, 1, 1, 0, 4};
+    const int rand2[] = {4, 5, 6, 7, 4};
+    const int rand3[] = {5, 5, 1, 6, 1};
+    const int rand4[] = {1, 5, 2, 7, 6, 1, 4, 2, 3, 2};
+    const int rand5[] = {7, 8, 5, 6, 7, 2, 1, 9, 10, 10};
+    const int rand6[] = {2, 8, 3, 4, 0};
+
+    const int ids1[] = {3, 0, 2, 1, 4};
+    const int ord1[] = {0, 1, 2, 3, 4};
+    const int ids2[] = {3, 9, 7, 0, 2, 1, 4, 8, 6, 5};
+    const int ord2[] = {0, 4, 7, 1, 2, 3, 9, 8, 6, 5};
+    const int ord3[] = {0, 3, 9, 2, 1, 8, 7, 6, 5, 4};
+    const int ids4[] = {9, 0, 1, 8, 6};
+    const int ord4[] = {1, 0, 4, 3, 2};
+
+    char buffer[20];
+    HDITEMA hdi;
+    int i;
+
+    hWndHeader = create_header_control();
+
+    ZeroMemory(&hdi, sizeof(HDITEMA));
+    hdi.mask = HDI_TEXT | HDI_LPARAM;
+    hdi.pszText = buffer;
+    strcpy(buffer, "test");
+
+    for (i = 0; i < 5; i++)
+    {
+        hdi.lParam = i;
+        SendMessage(hWndHeader, HDM_INSERTITEMA, rand1[i], (LPARAM)&hdi);
+        rand();
+    }
+    check_order(ids1, ord1, 5, "insert without iOrder");
+
+    hdi.mask |= HDI_ORDER;
+    for (i = 0; i < 5; i++)
+    {
+        hdi.lParam = i + 5;
+        hdi.iOrder = rand2[i];
+        SendMessage(hWndHeader, HDM_INSERTITEMA, rand3[i], (LPARAM)&hdi);
+        rand(); rand();
+    }
+    check_order(ids2, ord2, 10, "insert with order");
+
+    hdi.mask = HDI_ORDER;
+    for (i=0; i<10; i++)
+    {
+        hdi.iOrder = rand5[i];
+        SendMessage(hWndHeader, HDM_SETITEMA, rand4[i], (LPARAM)&hdi);
+        rand(); rand();
+    }
+    check_order(ids2, ord3, 10, "setitems changing order");
+
+    for (i=0; i<5; i++)
+        SendMessage(hWndHeader, HDM_DELETEITEM, rand6[i], 0);
+    check_order(ids4, ord4, 5, "deleteitem");
+
+    DestroyWindow(hWndHeader);
+}
+
+static LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    DRAWITEMSTRUCT *di;
     switch(msg) {
 
     case WM_NOTIFY:
@@ -489,29 +1434,49 @@ LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
         EXPECTEDNOTIFY *expected;
         int i;
 
+        if (hdr->hdr.code == NM_CUSTOMDRAW)
+            if (g_CustomDrawProc)
+                return g_CustomDrawProc(g_CustomDrawCount++, (NMCUSTOMDRAW*)hdr);
+
         for (i=0; i<nUnexpectedNotify; i++)
             ok(hdr->hdr.code != unexpectedNotify[i], "Received invalid notify %d\n", hdr->hdr.code);
-
+        
         if (nReceivedNotify >= nExpectedNotify || hdr->hdr.hwndFrom != hWndHeader )
             break;
 
         expected = &expectedNotify[nReceivedNotify];
         if (hdr->hdr.code != expected->iCode)
             break;
-
+        
         nReceivedNotify++;
         compare_items(hdr->hdr.code, &expected->hdItem, hdr->pitem, expected->fUnicode);
         break;
     }
 
+    case WM_DRAWITEM:
+        di = (DRAWITEMSTRUCT *)lParam;
+        ok(g_DrawItem.CtlType != 0, "Unexpected WM_DRAWITEM\n");
+        if (g_DrawItem.CtlType == 0) return 0;
+        g_DrawItemReceived = TRUE;
+        compare(di->CtlType,   g_DrawItem.CtlType, "%d");
+        compare(di->CtlID,     g_DrawItem.CtlID, "%d");
+        compare(di->hwndItem,  g_DrawItem.hwndItem, "%p");
+        compare(di->itemID,    g_DrawItem.itemID, "%d");
+        compare(di->itemState, g_DrawItem.itemState, "%d");
+        compare(di->rcItem.left,   g_DrawItem.rcItem.left, "%d");
+        compare(di->rcItem.top,    g_DrawItem.rcItem.top, "%d");
+        compare(di->rcItem.right,  g_DrawItem.rcItem.right, "%d");
+        compare(di->rcItem.bottom, g_DrawItem.rcItem.bottom, "%d");
+        break;
+
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
-
+  
     default:
         return DefWindowProcA(hWnd, msg, wParam, lParam);
     }
-
+    
     return 0L;
 }
 
@@ -528,23 +1493,48 @@ static void init(void) {
     wc.cbWndExtra = 0;
     wc.hInstance = GetModuleHandleA(NULL);
     wc.hIcon = NULL;
-    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
     wc.lpszClassName = "HeaderTestClass";
     wc.lpfnWndProc = HeaderTestWndProc;
     RegisterClassA(&wc);
 
-    hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW,
-      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
+      226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
+      NULL, NULL, GetModuleHandleA(NULL), 0);
     assert(hHeaderParentWnd != NULL);
+    ShowWindow(hHeaderParentWnd, SW_SHOW);
 }
 
 START_TEST(header)
 {
+    HWND parent_hwnd;
+
     init();
 
     test_header_control();
+    test_header_order();
+    test_customdraw();
 
     DestroyWindow(hHeaderParentWnd);
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+    parent_hwnd = create_custom_parent_window();
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent windows", FALSE);
+
+    test_hdm_index_messages(parent_hwnd);
+    test_hdm_getitemrect(parent_hwnd);
+    test_hdm_hittest(parent_hwnd);
+    test_hdm_layout(parent_hwnd);
+    test_hdm_ordertoindex(parent_hwnd);
+    test_hdm_sethotdivider(parent_hwnd);
+    test_hdm_imageMessages(parent_hwnd);
+    test_hdm_filterMessages(parent_hwnd);
+    test_hdm_unicodeformatMessages(parent_hwnd);
+    test_hdm_bitmapmarginMessages(parent_hwnd);
+
+    DestroyWindow(parent_hwnd);
+
 }
index 0ecb03a..3d4c333 100644 (file)
@@ -1,7 +1,9 @@
-/* Unit test suite for imagelist control.
+/*
+ * Unit test suite for imagelist control.
  *
  * Copyright 2004 Michael Stefaniuc
  * Copyright 2002 Mike McCormack for CodeWeavers
+ * Copyright 2007 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <assert.h>
-#include <windows.h>
-#include <commctrl.h>
+#define COBJMACROS
+#define CONST_VTABLE
+
+#include <stdarg.h>
 #include <stdio.h>
+#include <assert.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "objbase.h"
+#include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
 
 #include "wine/test.h"
 
 #define REDRAW(hwnd)
 #endif
 
+#define IMAGELIST_MAGIC (('L' << 8) | 'I')
+
+#include "pshpack2.h"
+/* Header used by ImageList_Read() and ImageList_Write() */
+typedef struct _ILHEAD
+{
+    USHORT     usMagic;
+    USHORT     usVersion;
+    WORD       cCurImage;
+    WORD       cMaxImage;
+    WORD       cGrow;
+    WORD       cx;
+    WORD       cy;
+    COLORREF   bkcolor;
+    WORD       flags;
+    SHORT      ovls[4];
+} ILHEAD;
+#include "poppack.h"
 
 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*) = NULL;
 
@@ -264,7 +293,7 @@ static void testHotspot (void)
             /* check new hotspot, it should be the same like the old one */
             himlNew = ImageList_GetDragImage(NULL, &ppt);
             ok(ppt.x == dx1 && ppt.y == dy1,
-                    "Expected drag hotspot [%d,%d] got [%ld,%ld]\n",
+                    "Expected drag hotspot [%d,%d] got [%d,%d]\n",
                     dx1, dy1, ppt.x, ppt.y);
             /* check size of new dragged image */
             ImageList_GetIconSize(himlNew, &newx, &newy);
@@ -283,6 +312,8 @@ static void testHotspot (void)
 #undef SIZEX2
 #undef SIZEY2
 #undef HOTSPOTS_MAX
+    ImageList_Destroy(himl2);
+    ImageList_Destroy(himl1);
     DestroyWindow(hwnd);
 }
 
@@ -327,13 +358,20 @@ static BOOL DoTest1(void)
     /* remove one extra */
     ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
 
+    /* check SetImageCount/GetImageCount */
+    ok(ImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
+    ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
+    ok(ImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
+    ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
+    ok(ImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
+    ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
+
     /* destroy it */
     ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
 
-    /* icons should be deleted by the imagelist */
-    ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n");
-    ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n");
-    ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\n");
+    ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
+    ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
+    ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
 
     return TRUE;
 }
@@ -366,10 +404,9 @@ static BOOL DoTest2(void)
     /* destroy it */
     ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
 
-    /* icons should be deleted by the imagelist */
-    ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n");
-    ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n");
-    ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\n");
+    ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
+    ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
+    ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
 
     return TRUE;
 }
@@ -541,10 +578,395 @@ static void testMerge(void)
 
     ImageList_Destroy(himl1);
     ImageList_Destroy(himl2);
-    DeleteObject(hicon1);
+    DestroyIcon(hicon1);
     DestroyWindow(hwnd);
 }
 
+/*********************** imagelist storage test ***************************/
+
+#define BMP_CX 48
+
+struct my_IStream
+{
+    IStream is;
+    char *iml_data; /* written imagelist data */
+    ULONG iml_data_size;
+};
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(
+    IStream* This,
+    REFIID riid,
+    void** ppvObject)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(
+    IStream* This)
+{
+    assert(0);
+    return 2;
+}
+
+static ULONG STDMETHODCALLTYPE Test_Stream_Release(
+    IStream* This)
+{
+    assert(0);
+    return 1;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Read(
+    IStream* This,
+    void* pv,
+    ULONG cb,
+    ULONG* pcbRead)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
+{
+    my_is->iml_data_size += add;
+
+    if (!my_is->iml_data)
+        my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size);
+    else
+        my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);
+
+    return my_is->iml_data ? TRUE : FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Write(
+    IStream* This,
+    const void* pv,
+    ULONG cb,
+    ULONG* pcbWritten)
+{
+    struct my_IStream *my_is = (struct my_IStream *)This;
+    ULONG current_iml_data_size = my_is->iml_data_size;
+
+    if (!allocate_storage(my_is, cb)) return E_FAIL;
+
+    memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
+    if (pcbWritten) *pcbWritten = cb;
+
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(
+    IStream* This,
+    LARGE_INTEGER dlibMove,
+    DWORD dwOrigin,
+    ULARGE_INTEGER* plibNewPosition)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(
+    IStream* This,
+    ULARGE_INTEGER libNewSize)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(
+    IStream* This,
+    IStream* pstm,
+    ULARGE_INTEGER cb,
+    ULARGE_INTEGER* pcbRead,
+    ULARGE_INTEGER* pcbWritten)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(
+    IStream* This,
+    DWORD grfCommitFlags)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(
+    IStream* This)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(
+    IStream* This,
+    ULARGE_INTEGER libOffset,
+    ULARGE_INTEGER cb,
+    DWORD dwLockType)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(
+    IStream* This,
+    ULARGE_INTEGER libOffset,
+    ULARGE_INTEGER cb,
+    DWORD dwLockType)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(
+    IStream* This,
+    STATSTG* pstatstg,
+    DWORD grfStatFlag)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(
+    IStream* This,
+    IStream** ppstm)
+{
+    assert(0);
+    return E_NOTIMPL;
+}
+
+static const IStreamVtbl Test_Stream_Vtbl =
+{
+    Test_Stream_QueryInterface,
+    Test_Stream_AddRef,
+    Test_Stream_Release,
+    Test_Stream_Read,
+    Test_Stream_Write,
+    Test_Stream_Seek,
+    Test_Stream_SetSize,
+    Test_Stream_CopyTo,
+    Test_Stream_Commit,
+    Test_Stream_Revert,
+    Test_Stream_LockRegion,
+    Test_Stream_UnlockRegion,
+    Test_Stream_Stat,
+    Test_Stream_Clone
+};
+
+static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
+
+static INT DIB_GetWidthBytes( int width, int bpp )
+{
+    int words;
+
+    switch (bpp)
+    {
+       case 1:  words = (width + 31) / 32; break;
+       case 4:  words = (width + 7) / 8; break;
+       case 8:  words = (width + 3) / 4; break;
+       case 15:
+       case 16: words = (width + 1) / 2; break;
+       case 24: words = (width * 3 + 3)/4; break;
+       case 32: words = width; break;
+
+        default:
+            words=0;
+            trace("Unknown depth %d, please report.\n", bpp );
+            assert(0);
+            break;
+    }
+    return 4 * words;
+}
+
+static void check_bitmap_data(const char *bm_data, ULONG bm_data_size,
+                              INT width, INT height, INT bpp,
+                              const char *comment)
+{
+    const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
+    const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
+    ULONG hdr_size, image_size;
+
+    hdr_size = sizeof(*bmfh) + sizeof(*bmih);
+    if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);
+
+    ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
+    ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
+    ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
+    ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
+    ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
+
+    ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
+    ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
+    ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
+    ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
+    ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
+
+    image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
+    ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
+#if 0
+{
+    char fname[256];
+    FILE *f;
+    sprintf(fname, "bmp_%s.bmp", comment);
+    f = fopen(fname, "wb");
+    fwrite(bm_data, 1, bm_data_size, f);
+    fclose(f);
+}
+#endif
+}
+
+static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max)
+{
+    ILHEAD *ilh = (ILHEAD *)ilh_data;
+
+    ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
+    ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
+    ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
+    ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
+    ok(ilh->cGrow == 4, "wrong cGrow %d (expected 4)\n", ilh->cGrow);
+    ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
+    ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
+    ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
+    ok(ilh->flags == ILC_COLOR24, "wrong flags %04x\n", ilh->flags);
+    ok(ilh->ovls[0] == -1, "wrong ovls[0] %04x\n", ilh->ovls[0]);
+    ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]);
+    ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]);
+    ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]);
+}
+
+static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
+{
+    HDC hdc;
+    char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
+    BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
+    HBITMAP hbmp, hbmp_old;
+    HBRUSH hbrush;
+    RECT rc = { 0, 0, cx, cy };
+
+    hdc = CreateCompatibleDC(0);
+
+    memset(bmi, 0, sizeof(*bmi));
+    bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
+    bmi->bmiHeader.biHeight = cx;
+    bmi->bmiHeader.biWidth = cy;
+    bmi->bmiHeader.biBitCount = 24;
+    bmi->bmiHeader.biPlanes = 1;
+    bmi->bmiHeader.biCompression = BI_RGB;
+    hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+    hbmp_old = SelectObject(hdc, hbmp);
+
+    hbrush = CreateSolidBrush(color);
+    FillRect(hdc, &rc, hbrush);
+    DeleteObject(hbrush);
+
+    DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+
+    SelectObject(hdc, hbmp_old);
+    DeleteDC(hdc);
+
+    return hbmp;
+}
+
+static void image_list_init(HIMAGELIST himl)
+{
+    HBITMAP hbm;
+    char comment[16];
+    INT n = 1;
+
+#define add_bitmap(grey) \
+    sprintf(comment, "%d", n++); \
+    hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
+    ImageList_Add(himl, hbm, NULL);
+
+    add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
+    add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
+    add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
+    add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
+    add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
+    add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
+#undef add_bitmap
+}
+
+#define iml_clear_stream_data() \
+    HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
+    Test_Stream.iml_data = NULL; \
+    Test_Stream.iml_data_size = 0;
+
+static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max,
+                           INT width, INT height, INT bpp, const char *comment)
+{
+    INT ret, cxx, cyy;
+
+    ret = ImageList_GetImageCount(himl);
+    ok(ret == cur, "expected cur %d got %d\n", cur, ret);
+
+    ret = ImageList_GetIconSize(himl, &cxx, &cyy);
+    ok(ret, "ImageList_GetIconSize failed\n");
+    ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
+    ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
+
+    iml_clear_stream_data();
+    ret = ImageList_Write(himl, &Test_Stream.is);
+    ok(ret, "ImageList_Write failed\n");
+
+    ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
+    ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
+
+    check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max);
+    check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
+                      Test_Stream.iml_data_size - sizeof(ILHEAD),
+                      width, height, bpp, comment);
+}
+
+static void test_imagelist_storage(void)
+{
+    HIMAGELIST himl;
+    BOOL ret;
+
+    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
+    ok(himl != 0, "ImageList_Create failed\n");
+
+    check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, BMP_CX * 4, BMP_CX * 1, 24, "empty");
+
+    image_list_init(himl);
+    check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, BMP_CX * 4, BMP_CX * 7, 24, "orig");
+
+    ret = ImageList_Remove(himl, 4);
+    ok(ret, "ImageList_Remove failed\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, BMP_CX * 4, BMP_CX * 7, 24, "1");
+
+    ret = ImageList_Remove(himl, 5);
+    ok(ret, "ImageList_Remove failed\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, BMP_CX * 4, BMP_CX * 7, 24, "2");
+
+    ret = ImageList_Remove(himl, 6);
+    ok(ret, "ImageList_Remove failed\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, BMP_CX * 4, BMP_CX * 7, 24, "3");
+
+    ret = ImageList_Remove(himl, 7);
+    ok(ret, "ImageList_Remove failed\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "4");
+
+    ret = ImageList_Remove(himl, -2);
+    ok(!ret, "ImageList_Remove(-2) should fail\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "5");
+
+    ret = ImageList_Remove(himl, 20);
+    ok(!ret, "ImageList_Remove(20) should fail\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "6");
+
+    ret = ImageList_Remove(himl, -1);
+    ok(ret, "ImageList_Remove(-1) failed\n");
+    check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, BMP_CX * 4, BMP_CX * 1, 24, "7");
+
+    ret = ImageList_Destroy(himl);
+    ok(ret, "ImageList_Destroy failed\n");
+
+    iml_clear_stream_data();
+}
+
 START_TEST(imagelist)
 {
     desktopDC=GetDC(NULL);
@@ -557,4 +979,5 @@ START_TEST(imagelist)
     DoTest2();
     DoTest3();
     testMerge();
+    test_imagelist_storage();
 }
index e8d147d..9138442 100644 (file)
@@ -2,6 +2,7 @@
  * ListView tests
  *
  * Copyright 2006 Mike McCormack for CodeWeavers
+ * Copyright 2007 George Gov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <commctrl.h>
 
 #include "wine/test.h"
+#include "msg.h"
+
+#define PARENT_SEQ_INDEX    0
+#define LISTVIEW_SEQ_INDEX  1
+#define NUM_MSG_SEQUENCES   2
+
+#define LISTVIEW_ID 0
+#define HEADER_ID   1
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+#define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
+       "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
+
+HWND hwndparent;
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message create_parent_wnd_seq[] = {
+    { WM_GETMINMAXINFO,     sent },
+    { WM_NCCREATE,          sent },
+    { WM_NCCALCSIZE,        sent|wparam, 0 },
+    { WM_CREATE,            sent },
+    { WM_SHOWWINDOW,        sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_ACTIVATEAPP,       sent|wparam, 1 },
+    { WM_NCACTIVATE,        sent|wparam, 1 },
+    { WM_ACTIVATE,          sent|wparam, 1 },
+    { WM_IME_SETCONTEXT,    sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY,        sent|defwinproc|optional },
+    { WM_SETFOCUS,          sent|wparam|defwinproc, 0 },
+    /* Win9x adds SWP_NOZORDER below */
+    { WM_WINDOWPOSCHANGED,  sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+    { WM_NCCALCSIZE,        sent|wparam|optional, 1 },
+    { WM_SIZE,              sent },
+    { WM_MOVE,              sent },
+    { 0 }
+};
+
+static const struct message redraw_listview_seq[] = {
+    { WM_PAINT,      sent|id,            0, 0, LISTVIEW_ID },
+    { WM_PAINT,      sent|id,            0, 0, HEADER_ID },
+    { WM_NCPAINT,    sent|id|defwinproc, 0, 0, HEADER_ID },
+    { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, HEADER_ID },
+    { WM_NOTIFY,     sent|id|defwinproc, 0, 0, LISTVIEW_ID },
+    { WM_NCPAINT,    sent|id|defwinproc, 0, 0, LISTVIEW_ID },
+    { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
+    { 0 }
+};
+
+static const struct message listview_icon_spacing_seq[] = {
+    { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(20, 30) },
+    { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(25, 35) },
+    { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(-1, -1) },
+    { 0 }
+};
+
+static const struct message listview_color_seq[] = {
+    { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(0,0,0) },
+    { LVM_GETBKCOLOR,     sent },
+    { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(0,0,0) },
+    { LVM_GETTEXTCOLOR,   sent },
+    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
+    { LVM_GETTEXTBKCOLOR, sent },
+
+    { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(100,50,200) },
+    { LVM_GETBKCOLOR,     sent },
+    { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(100,50,200) },
+    { LVM_GETTEXTCOLOR,   sent },
+    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
+    { LVM_GETTEXTBKCOLOR, sent },
+
+    { LVM_SETBKCOLOR,     sent|lparam, 0, CLR_NONE },
+    { LVM_GETBKCOLOR,     sent },
+    { LVM_SETTEXTCOLOR,   sent|lparam, 0, CLR_NONE },
+    { LVM_GETTEXTCOLOR,   sent },
+    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
+    { LVM_GETTEXTBKCOLOR, sent },
+
+    { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(255,255,255) },
+    { LVM_GETBKCOLOR,     sent },
+    { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(255,255,255) },
+    { LVM_GETTEXTCOLOR,   sent },
+    { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
+    { LVM_GETTEXTBKCOLOR, sent },
+    { 0 }
+};
+
+static const struct message listview_item_count_seq[] = {
+    { LVM_GETITEMCOUNT,   sent },
+    { LVM_INSERTITEM,     sent },
+    { LVM_INSERTITEM,     sent },
+    { LVM_INSERTITEM,     sent },
+    { LVM_GETITEMCOUNT,   sent },
+    { LVM_DELETEITEM,     sent|wparam, 2 },
+    { LVM_GETITEMCOUNT,   sent },
+    { LVM_DELETEALLITEMS, sent },
+    { LVM_GETITEMCOUNT,   sent },
+    { LVM_INSERTITEM,     sent },
+    { LVM_INSERTITEM,     sent },
+    { LVM_GETITEMCOUNT,   sent },
+    { LVM_INSERTITEM,     sent },
+    { LVM_GETITEMCOUNT,   sent },
+    { 0 }
+};
+
+static const struct message listview_itempos_seq[] = {
+    { LVM_INSERTITEM,      sent },
+    { LVM_INSERTITEM,      sent },
+    { LVM_INSERTITEM,      sent },
+    { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
+    { LVM_GETITEMPOSITION, sent|wparam,        1 },
+    { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
+    { LVM_GETITEMPOSITION, sent|wparam,        2 },
+    { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
+    { LVM_GETITEMPOSITION, sent|wparam,        0 },
+    { 0 }
+};
+
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL register_parent_wnd_class(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Listview test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND create_parent_window(void)
+{
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindowEx(0, "Listview test parent class",
+                          "Listview test parent window",
+                          WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                          WS_MAXIMIZEBOX | WS_VISIBLE,
+                          0, 0, 100, 100,
+                          GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
+}
+
+static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    msg.id = LISTVIEW_ID;
+    add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+    return ret;
+}
+
+static HWND create_listview_control(void)
+{
+    struct subclass_info *info;
+    HWND hwnd;
+    RECT rect;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    GetClientRect(hwndparent, &rect);
+    hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
+                           WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
+                           0, 0, rect.right, rect.bottom,
+                           hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+    ok(hwnd != NULL, "gle=%d\n", GetLastError());
+
+    if (!hwnd)
+    {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                            (LONG_PTR)listview_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+
+    return hwnd;
+}
+
+static HWND create_custom_listview_control(DWORD style)
+{
+    struct subclass_info *info;
+    HWND hwnd;
+    RECT rect;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    GetClientRect(hwndparent, &rect);
+    hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
+                           WS_CHILD | WS_BORDER | WS_VISIBLE | style,
+                           0, 0, rect.right, rect.bottom,
+                           hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+    ok(hwnd != NULL, "gle=%d\n", GetLastError());
+
+    if (!hwnd)
+    {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                            (LONG_PTR)listview_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+
+    return hwnd;
+}
+
+static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    msg.id = HEADER_ID;
+    add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+    return ret;
+}
+
+static HWND subclass_header(HWND hwndListview)
+{
+    struct subclass_info *info;
+    HWND hwnd;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    hwnd = ListView_GetHeader(hwndListview);
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                            (LONG_PTR)header_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+
+    return hwnd;
+}
 
 static void test_images(void)
 {
-    HWND hwnd, hwndparent = 0;
+    HWND hwnd;
     DWORD r;
     LVITEM item;
     HIMAGELIST himl;
@@ -43,7 +352,7 @@ static void test_images(void)
     r = ImageList_Add(himl, hbmp, 0);
     ok(r == 0, "should be zero\n");
 
-    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
+    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 
                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
     ok(hwnd != NULL, "failed to create listview window\n");
 
@@ -63,6 +372,7 @@ static void test_images(void)
     item.iItem = 0;
     item.iSubItem = 1;
     item.iImage = 0;
+    item.pszText = 0;
     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
     ok(r == -1, "should fail\n");
 
@@ -94,14 +404,14 @@ static void test_images(void)
 
 static void test_checkboxes(void)
 {
-    HWND hwnd, hwndparent = 0;
+    HWND hwnd;
     LVITEMA item;
     DWORD r;
     static CHAR text[]  = "Text",
                 text2[] = "Text2",
                 text3[] = "Text3";
 
-    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
+    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 
                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
     ok(hwnd != NULL, "failed to create listview window\n");
 
@@ -113,7 +423,7 @@ static void test_checkboxes(void)
     item.iSubItem = 0;
     item.pszText = text;
     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
-    ok(r == 0, "ret %ld\n", r);
+    ok(r == 0, "ret %d\n", r);
 
     item.iItem = 0;
     item.mask = LVIF_STATE;
@@ -129,7 +439,7 @@ static void test_checkboxes(void)
     item.iSubItem = 0;
     item.pszText = text;
     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
-    ok(r == 1, "ret %ld\n", r);
+    ok(r == 1, "ret %d\n", r);
 
     item.iItem = 1;
     item.mask = LVIF_STATE;
@@ -147,13 +457,13 @@ static void test_checkboxes(void)
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
     ok(item.state == 0x1ccc, "state %x\n", item.state);
 
-    /* Now add an item without specifying a state and check that it's state goes to 0x1000 */
+    /* Now add an item without specifying a state and check that its state goes to 0x1000 */
     item.iItem = 2;
     item.mask = LVIF_TEXT;
     item.state = 0;
     item.pszText = text2;
     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
-    ok(r == 2, "ret %ld\n", r);
+    ok(r == 2, "ret %d\n", r);
 
     item.iItem = 2;
     item.mask = LVIF_STATE;
@@ -161,14 +471,14 @@ static void test_checkboxes(void)
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
     ok(item.state == 0x1000, "state %x\n", item.state);
 
-    /* Add a further item this time specifying a state and still it's state goes to 0x1000 */
+    /* Add a further item this time specifying a state and still its state goes to 0x1000 */
     item.iItem = 3;
     item.mask = LVIF_TEXT | LVIF_STATE;
     item.stateMask = 0xffff;
     item.state = 0x2aaa;
     item.pszText = text3;
     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
-    ok(r == 3, "ret %ld\n", r);
+    ok(r == 3, "ret %d\n", r);
 
     item.iItem = 3;
     item.mask = LVIF_STATE;
@@ -189,9 +499,19 @@ static void test_checkboxes(void)
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
     ok(item.state == 0x2aaa, "state %x\n", item.state);
 
+    /* Check that only the bits we asked for are returned,
+     * and that all the others are set to zero
+     */
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xf000;
+    item.state = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x2000, "state %x\n", item.state);
+
     /* Set the style again and check that doesn't change an item's state */
     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
-    ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
+    ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
 
     item.iItem = 3;
     item.mask = LVIF_STATE;
@@ -201,7 +521,7 @@ static void test_checkboxes(void)
 
     /* Unsetting the checkbox extended style doesn't change an item's state */
     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
-    ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
+    ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
 
     item.iItem = 3;
     item.mask = LVIF_STATE;
@@ -211,7 +531,7 @@ static void test_checkboxes(void)
 
     /* Now setting the style again will change an item's state */
     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
-    ok(r == 0, "ret %lx\n", r);
+    ok(r == 0, "ret %x\n", r);
 
     item.iItem = 3;
     item.mask = LVIF_STATE;
@@ -222,6 +542,502 @@ static void test_checkboxes(void)
     DestroyWindow(hwnd);
 }
 
+static void insert_column(HWND hwnd, int idx)
+{
+    LVCOLUMN column;
+    DWORD rc;
+
+    memset(&column, 0xaa, sizeof(column));
+    column.mask = LVCF_SUBITEM;
+    column.iSubItem = idx;
+
+    rc = ListView_InsertColumn(hwnd, idx, &column);
+    expect(idx, rc);
+}
+
+static void insert_item(HWND hwnd, int idx)
+{
+    static CHAR text[] = "foo";
+
+    LVITEMA item;
+    DWORD rc;
+
+    memset(&item, 0xaa, sizeof (item));
+    item.mask = LVIF_TEXT;
+    item.iItem = idx;
+    item.iSubItem = 0;
+    item.pszText = text;
+
+    rc = ListView_InsertItem(hwnd, &item);
+    expect(idx, rc);
+}
+
+static void test_items(void)
+{
+    const LPARAM lparamTest = 0x42;
+    HWND hwnd;
+    LVITEMA item;
+    DWORD r;
+    static CHAR text[] = "Text";
+
+    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
+                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
+    ok(hwnd != NULL, "failed to create listview window\n");
+
+    /*
+     * Test setting/getting item params
+     */
+
+    /* Set up two columns */
+    insert_column(hwnd, 0);
+    insert_column(hwnd, 1);
+
+    /* Insert an item with just a param */
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_PARAM;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    item.lParam = lparamTest;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
+    ok(r == 0, "ret %d\n", r);
+
+    /* Test getting of the param */
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_PARAM;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+    ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
+
+    /* Set up a subitem */
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_TEXT;
+    item.iItem = 0;
+    item.iSubItem = 1;
+    item.pszText = text;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+
+    /* Query param from subitem: returns main item param */
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_PARAM;
+    item.iItem = 0;
+    item.iSubItem = 1;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+    ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
+
+    /* Set up param on first subitem: no effect */
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_PARAM;
+    item.iItem = 0;
+    item.iSubItem = 1;
+    item.lParam = lparamTest+1;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
+    ok(r == 0, "ret %d\n", r);
+
+    /* Query param from subitem again: should still return main item param */
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_PARAM;
+    item.iItem = 0;
+    item.iSubItem = 1;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+    ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
+
+    /**** Some tests of state highlighting ****/
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_STATE;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    item.state = LVIS_SELECTED;
+    item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+    item.iSubItem = 1;
+    item.state = LVIS_DROPHILITED;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+
+    memset (&item, 0xaa, sizeof (item));
+    item.mask = LVIF_STATE;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    item.stateMask = -1;
+    r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+    ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
+    item.iSubItem = 1;
+    r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
+    ok(r != 0, "ret %d\n", r);
+    todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_columns(void)
+{
+    HWND hwnd;
+    LVCOLUMN column;
+    DWORD rc;
+
+    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
+                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
+    ok(hwnd != NULL, "failed to create listview window\n");
+
+    /* Add a column with no mask */
+    memset(&column, 0xaa, sizeof(column));
+    column.mask = 0;
+    rc = ListView_InsertColumn(hwnd, 0, &column);
+    ok(rc==0, "Inserting column with no mask failed with %d\n", rc);
+
+    /* Check its width */
+    rc = ListView_GetColumnWidth(hwnd, 0);
+    ok(rc==10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
+
+    DestroyWindow(hwnd);
+}
+/* test setting imagelist between WM_NCCREATE and WM_CREATE */
+static WNDPROC listviewWndProc;
+static HIMAGELIST test_create_imagelist;
+
+static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    if (uMsg == WM_CREATE)
+    {
+        LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
+        lpcs->style |= LVS_REPORT;
+        SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
+    }
+    return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
+}
+
+static void test_create(void)
+{
+    HWND hList;
+    HWND hHeader;
+    WNDCLASSEX cls;
+    cls.cbSize = sizeof(WNDCLASSEX);
+    ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
+    listviewWndProc = cls.lpfnWndProc;
+    cls.lpfnWndProc = create_test_wndproc;
+    cls.lpszClassName = "MyListView32";
+    ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
+
+    test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
+    hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
+    ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
+    hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
+    DestroyWindow(hList);
+}
+
+static void test_redraw(void)
+{
+    HWND hwnd, hwndheader;
+
+    hwnd = create_listview_control();
+    hwndheader = subclass_header(hwnd);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    trace("invalidate & update\n");
+    InvalidateRect(hwnd, NULL, TRUE);
+    UpdateWindow(hwnd);
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    DestroyWindow(hwnd);
+}
+
+static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+    COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
+
+    if(msg == WM_NOTIFY) {
+        NMHDR *nmhdr = (PVOID)lp;
+        if(nmhdr->code == NM_CUSTOMDRAW) {
+            NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
+            trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
+            switch(nmlvcd->nmcd.dwDrawStage) {
+            case CDDS_PREPAINT:
+                SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
+                return CDRF_NOTIFYITEMDRAW;
+            case CDDS_ITEMPREPAINT:
+                nmlvcd->clrTextBk = CLR_DEFAULT;
+                return CDRF_NOTIFYSUBITEMDRAW;
+            case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
+                clr = GetBkColor(nmlvcd->nmcd.hdc);
+                todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
+                return CDRF_NOTIFYPOSTPAINT;
+            case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
+                clr = GetBkColor(nmlvcd->nmcd.hdc);
+                todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
+                return CDRF_DODEFAULT;
+            }
+            return CDRF_DODEFAULT;
+        }
+    }
+
+    return DefWindowProcA(hwnd, msg, wp, lp);
+}
+
+static void test_customdraw(void)
+{
+    HWND hwnd;
+    WNDPROC oldwndproc;
+
+    hwnd = create_listview_control();
+
+    insert_column(hwnd, 0);
+    insert_column(hwnd, 1);
+    insert_item(hwnd, 0);
+
+    oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
+                                           (LONG_PTR)cd_wndproc);
+
+    InvalidateRect(hwnd, NULL, TRUE);
+    UpdateWindow(hwnd);
+
+    SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_icon_spacing(void)
+{
+    /* LVM_SETICONSPACING */
+    /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
+    /* note: the first test will fail if the default icon spacing is not (43,43) */
+
+    HWND hwnd;
+    DWORD r;
+
+    hwnd = create_custom_listview_control(LVS_ICON);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    trace("test icon spacing\n");
+    todo_wine {
+        r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(20, 30));
+        expect(MAKELONG(43,43), r);
+    }
+        r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(25, 35));
+        expect(MAKELONG(20,30), r);
+        r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1,-1));
+        expect(MAKELONG(25,35), r);
+
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+}
+
+static void test_color(void)
+{
+    /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
+
+    HWND hwnd;
+    DWORD r;
+    int i;
+
+    COLORREF color;
+    COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
+
+    hwnd = create_listview_control();
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    trace("test color seq\n");
+    for (i = 0; i < 4; i++)
+    {
+        color = colors[i];
+
+        r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
+        expect(TRUE, r);
+        r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color);
+        expect(color, r);
+
+        r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
+        expect (TRUE, r);
+        r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color);
+        expect(color, r);
+
+        r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
+        expect(TRUE, r);
+        r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color);
+        expect(color, r);
+    }
+
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+}
+
+static void test_item_count(void)
+{
+    /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
+
+    HWND hwnd;
+    DWORD r;
+
+    LVITEM item0;
+    LVITEM item1;
+    LVITEM item2;
+    static CHAR item0text[] = "item0";
+    static CHAR item1text[] = "item1";
+    static CHAR item2text[] = "item2";
+
+    hwnd = create_listview_control();
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    trace("test item count\n");
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    expect(0, r);
+
+    /* [item0] */
+    item0.mask = LVIF_TEXT;
+    item0.iItem = 0;
+    item0.iSubItem = 0;
+    item0.pszText = item0text;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
+    expect(0, r);
+
+    /* [item0, item1] */
+    item1.mask = LVIF_TEXT;
+    item1.iItem = 1;
+    item1.iSubItem = 0;
+    item1.pszText = item1text;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
+    expect(1, r);
+
+    /* [item0, item1, item2] */
+    item2.mask = LVIF_TEXT;
+    item2.iItem = 2;
+    item2.iSubItem = 0;
+    item2.pszText = item2text;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
+    expect(2, r);
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    expect(3, r);
+
+    /* [item0, item1] */
+    r = SendMessage(hwnd, LVM_DELETEITEM, (WPARAM) 2, 0);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    expect(2, r);
+
+    /* [] */
+    r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    expect(0, r);
+
+    /* [item0] */
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
+    expect(0, r);
+
+    /* [item0, item1] */
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
+    expect(1, r);
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    expect(2, r);
+
+    /* [item0, item1, item2] */
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
+    expect(2, r);
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    expect(3, r);
+
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+}
+
+static void test_item_position(void)
+{
+    /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
+
+    HWND hwnd;
+    DWORD r;
+    POINT position;
+
+    LVITEM item0;
+    LVITEM item1;
+    LVITEM item2;
+    static CHAR item0text[] = "item0";
+    static CHAR item1text[] = "item1";
+    static CHAR item2text[] = "item2";
+
+    hwnd = create_custom_listview_control(LVS_ICON);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    trace("test item position\n");
+
+    /* [item0] */
+    item0.mask = LVIF_TEXT;
+    item0.iItem = 0;
+    item0.iSubItem = 0;
+    item0.pszText = item0text;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
+    expect(0, r);
+
+    /* [item0, item1] */
+    item1.mask = LVIF_TEXT;
+    item1.iItem = 1;
+    item1.iSubItem = 0;
+    item1.pszText = item1text;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
+    expect(1, r);
+
+    /* [item0, item1, item2] */
+    item2.mask = LVIF_TEXT;
+    item2.iItem = 2;
+    item2.iSubItem = 0;
+    item2.pszText = item2text;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
+    expect(2, r);
+
+    r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
+    expect(TRUE, r);
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
+    expect(TRUE, r);
+    expect2(10, 5, position.x, position.y);
+
+    r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
+    expect(TRUE, r);
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
+    expect(TRUE, r);
+    expect2(0, 0, position.x, position.y);
+
+    r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
+    expect(TRUE, r);
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
+    expect(TRUE, r);
+    expect2(20, 20, position.x, position.y);
+
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+}
+
 START_TEST(listview)
 {
     INITCOMMONCONTROLSEX icc;
@@ -230,6 +1046,22 @@ START_TEST(listview)
     icc.dwSize = sizeof icc;
     InitCommonControlsEx(&icc);
 
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hwndparent = create_parent_window();
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent window", TRUE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
     test_images();
     test_checkboxes();
+    test_items();
+    test_create();
+    test_redraw();
+    test_customdraw();
+    test_icon_spacing();
+    test_color();
+    test_item_count();
+    test_item_position();
+    test_columns();
 }
diff --git a/rostests/winetests/comctl32/misc.c b/rostests/winetests/comctl32/misc.c
new file mode 100644 (file)
index 0000000..881f0b0
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Misc tests
+ *
+ * Copyright 2006 Paul Vriens
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+#include "wine/test.h"
+
+static PVOID (WINAPI * pAlloc)(LONG);
+static PVOID (WINAPI * pReAlloc)(PVOID, LONG);
+static BOOL (WINAPI * pFree)(PVOID);
+static LONG (WINAPI * pGetSize)(PVOID);
+
+static INT (WINAPI * pStr_GetPtrA)(LPCSTR, LPSTR, INT);
+static BOOL (WINAPI * pStr_SetPtrA)(LPSTR, LPCSTR);
+static INT (WINAPI * pStr_GetPtrW)(LPCWSTR, LPWSTR, INT);
+static BOOL (WINAPI * pStr_SetPtrW)(LPWSTR, LPCWSTR);
+
+static HMODULE hComctl32 = 0;
+
+#define COMCTL32_GET_PROC(ordinal, func) \
+    p ## func = (void*)GetProcAddress(hComctl32, (LPSTR)ordinal); \
+    if(!p ## func) { \
+      trace("GetProcAddress(%d)(%s) failed\n", ordinal, #func); \
+      FreeLibrary(hComctl32); \
+    }
+
+#define expect(expected, got) ok(expected == got, "expected %d, got %d\n", expected,got)
+
+static BOOL InitFunctionPtrs(void)
+{
+    hComctl32 = LoadLibraryA("comctl32.dll");
+
+    if(!hComctl32)
+    {
+        trace("Could not load comctl32.dll\n");
+        return FALSE;
+    }
+
+    COMCTL32_GET_PROC(71, Alloc);
+    COMCTL32_GET_PROC(72, ReAlloc);
+    COMCTL32_GET_PROC(73, Free);
+    COMCTL32_GET_PROC(74, GetSize);
+
+    COMCTL32_GET_PROC(233, Str_GetPtrA)
+    COMCTL32_GET_PROC(234, Str_SetPtrA)
+    COMCTL32_GET_PROC(235, Str_GetPtrW)
+    COMCTL32_GET_PROC(236, Str_SetPtrW)
+
+    return TRUE;
+}
+
+static void test_GetPtrAW(void)
+{
+    if (pStr_GetPtrA)
+    {
+        static const char source[] = "Just a source string";
+        static const char desttest[] = "Just a destination string";
+        static char dest[MAX_PATH];
+        int sourcelen;
+        int destsize = MAX_PATH;
+        int count = -1;
+
+        sourcelen = strlen(source) + 1;
+
+        count = pStr_GetPtrA(NULL, NULL, 0);
+        ok (count == 0, "Expected count to be 0, it was %d\n", count);
+
+        if (0)
+        {
+            /* Crashes on W98, NT4, W2K, XP, W2K3
+             * Our implementation also crashes and we should probably leave
+             * it like that.
+             */
+            count = -1;
+            count = pStr_GetPtrA(NULL, NULL, destsize);
+            trace("count : %d\n", count);
+        }
+
+        count = 0;
+        count = pStr_GetPtrA(source, NULL, 0);
+        ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count);
+
+        count = 0;
+        strcpy(dest, desttest);
+        count = pStr_GetPtrA(source, dest, 0);
+        ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count);
+        ok (!lstrcmp(dest, desttest), "Expected destination to not have changed\n");
+
+        count = 0;
+        count = pStr_GetPtrA(source, NULL, destsize);
+        ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count);
+
+        count = 0;
+        count = pStr_GetPtrA(source, dest, destsize);
+        ok (count == sourcelen, "Expected count to be %d, it was %d\n", sourcelen , count);
+        ok (!lstrcmp(source, dest), "Expected source and destination to be the same\n");
+
+        count = -1;
+        strcpy(dest, desttest);
+        count = pStr_GetPtrA(NULL, dest, destsize);
+        ok (count == 0, "Expected count to be 0, it was %d\n", count);
+        ok (dest[0] == '\0', "Expected destination to be cut-off and 0 terminated\n");
+
+        count = 0;
+        destsize = 15;
+        count = pStr_GetPtrA(source, dest, destsize);
+        ok (count == 15, "Expected count to be 15, it was %d\n", count);
+        ok (!memcmp(source, dest, 14), "Expected first part of source and destination to be the same\n");
+        ok (dest[14] == '\0', "Expected destination to be cut-off and 0 terminated\n");
+    }
+}
+
+static void test_Alloc(void)
+{
+    PCHAR p = pAlloc(0);
+    ok(p != NULL, "p=%p\n", p);
+    ok(pFree(p), "\n");
+    p = pAlloc(1);
+    ok(p != NULL, "\n");
+    *p = '\0';
+    expect(1, pGetSize(p));
+    p = pReAlloc(p, 2);
+    ok(p != NULL, "\n");
+    expect(2, pGetSize(p));
+    ok(pFree(p), "\n");
+    ok(pFree(NULL), "\n");
+    p = pReAlloc(NULL, 2);
+    ok(p != NULL, "\n");
+    ok(pFree(p), "\n");
+}
+
+START_TEST(misc)
+{
+    if(!InitFunctionPtrs())
+        return;
+
+    test_GetPtrAW();
+    test_Alloc();
+
+    FreeLibrary(hComctl32);
+}
index 89c9ae4..fae4a37 100644 (file)
@@ -2,6 +2,7 @@
  * comctl32 month calendar unit tests
  *
  * Copyright (C) 2006 Vitaliy Margolen
+ * Copyright (C) 2007 Farshad Agah
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include <stdarg.h>
 
-#include "windows.h"
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
 
 #include "commctrl.h"
 
 #include "wine/test.h"
+#include <assert.h>
+#include <windows.h>
+#include "msg.h"
 
-void test_monthcal(void)
+#define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got);
+
+#define NUM_MSG_SEQUENCES   2
+#define PARENT_SEQ_INDEX    0
+#define MONTHCAL_SEQ_INDEX  1
+
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message create_parent_window_seq[] = {
+    { WM_GETMINMAXINFO, sent },
+    { WM_NCCREATE, sent },
+    { WM_NCCALCSIZE, sent|wparam, 0 },
+    { WM_CREATE, sent },
+    { WM_SHOWWINDOW, sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|defwinproc|optional },
+    { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    /* Win9x adds SWP_NOZORDER below */
+    { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+    { WM_SIZE, sent },
+    { WM_MOVE, sent },
+    { 0 }
+};
+
+static const struct message create_monthcal_control_seq[] = {
+    { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
+    { WM_QUERYUISTATE, sent },
+    { WM_GETFONT, sent },
+    { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
+    { 0 }
+};
+
+static const struct message create_monthcal_multi_sel_style_seq[] = {
+    { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
+    { WM_QUERYUISTATE, sent },
+    { WM_GETFONT, sent },
+    { 0 }
+};
+
+static const struct message monthcal_color_seq[] = {
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(0,0,0)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255,255,255)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0},
+
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(0,0,0)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255,255,255)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0},
+
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(0,0,0)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255,255,255)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TEXT, 0},
+
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(0,0,0)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255,255,255)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0},
+
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(0,0,0)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255,255,255)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0},
+
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(0,0,0)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
+    { MCM_SETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255,255,255)},
+    { MCM_GETCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0},
+    { 0 }
+};
+
+static const struct message monthcal_curr_date_seq[] = {
+    { MCM_SETCURSEL, sent|wparam, 0},
+    { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
+    { WM_ERASEBKGND, sent|lparam|defwinproc, 0},
+    { MCM_SETCURSEL, sent|wparam, 0},
+    { MCM_SETCURSEL, sent|wparam, 0},
+    { MCM_GETCURSEL, sent|wparam, 0},
+    { MCM_GETCURSEL, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+static const struct message monthcal_first_day_seq[] = {
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -5},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -4},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -3},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -2},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, -1},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 1},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 2},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 3},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 4},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 5},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 6},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 7},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 8},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 9},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 10},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+
+    { MCM_SETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 11},
+    { MCM_GETFIRSTDAYOFWEEK, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+static const struct message monthcal_unicode_seq[] = {
+    { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
+    { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
+    { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
+    { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
+    { MCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0},
+    { MCM_SETUNICODEFORMAT, sent|wparam|lparam, 1, 0},
+    { 0 }
+};
+
+static const struct message monthcal_hit_test_seq[] = {
+    { MCM_SETCURSEL, sent|wparam, 0},
+    { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_HITTEST, sent|wparam, 0},
+    { 0 }
+};
+
+static const struct message monthcal_todaylink_seq[] = {
+    { MCM_HITTEST, sent|wparam, 0},
+    { MCM_SETTODAY, sent|wparam, 0},
+    { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
+    { MCM_GETTODAY, sent|wparam, 0},
+    { WM_LBUTTONDOWN, sent|wparam|lparam, MK_LBUTTON, MAKELONG(70, 370)},
+    { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0},
+    { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
+    { MCM_GETCURSEL, sent|wparam, 0},
+    { 0 }
+};
+
+static const struct message monthcal_today_seq[] = {
+    { MCM_SETTODAY, sent|wparam, 0},
+    { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
+    { MCM_GETTODAY, sent|wparam, 0},
+    { MCM_SETTODAY, sent|wparam, 0},
+    { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
+    { MCM_GETTODAY, sent|wparam, 0},
+    { 0 }
+};
+
+static const struct message monthcal_scroll_seq[] = {
+    { MCM_SETMONTHDELTA, sent|wparam|lparam, 2, 0},
+    { MCM_SETMONTHDELTA, sent|wparam|lparam, 3, 0},
+    { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
+    { MCM_SETMONTHDELTA, sent|wparam|lparam, 12, 0},
+    { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
+    { MCM_SETMONTHDELTA, sent|wparam|lparam, 15, 0},
+    { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
+    { MCM_SETMONTHDELTA, sent|wparam|lparam, -5, 0},
+    { MCM_GETMONTHDELTA, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+static const struct message monthcal_monthrange_seq[] = {
+    { MCM_GETMONTHRANGE, sent|wparam, GMR_VISIBLE},
+    { MCM_GETMONTHRANGE, sent|wparam, GMR_DAYSTATE},
+    { 0 }
+};
+
+static const struct message monthcal_max_sel_day_seq[] = {
+    { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 5, 0},
+    { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
+    { MCM_SETMAXSELCOUNT, sent|wparam|lparam, 15, 0},
+    { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
+    { MCM_SETMAXSELCOUNT, sent|wparam|lparam, -1, 0},
+    { MCM_GETMAXSELCOUNT, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+/* expected message sequence for parent*/
+static const struct message destroy_monthcal_parent_msgs_seq[] = {
+    { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY},
+    { 0 }
+};
+
+/* expected message sequence for child*/
+static const struct message destroy_monthcal_child_msgs_seq[] = {
+    { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0},
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0},
+    { WM_WINDOWPOSCHANGED, sent|wparam, 0},
+    { WM_DESTROY, sent|wparam|lparam, 0, 0},
+    { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+static const struct message destroy_monthcal_multi_sel_style_seq[] = {
+    { WM_DESTROY, sent|wparam|lparam, 0, 0},
+    { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+/* expected message sequence for parent window*/
+static const struct message destroy_parent_seq[] = {
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0},
+    { WM_WINDOWPOSCHANGED, sent|wparam, 0},
+    { WM_NCACTIVATE, sent|wparam|lparam, 0, 0},
+    { WM_ACTIVATE, sent|wparam|lparam, 0, 0},
+    { WM_ACTIVATEAPP, sent|wparam, 0},
+    { WM_KILLFOCUS, sent|wparam|lparam, 0, 0},
+    { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
+    { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
+    { WM_DESTROY, sent|wparam|lparam, 0, 0},
+    { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
+    { 0 }
+};
+
+static void test_monthcal(void)
 {
     HWND hwnd;
     SYSTEMTIME st[2], st1[2];
@@ -88,9 +372,787 @@ void test_monthcal(void)
     st[1].wYear += 4;
     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
+
+    DestroyWindow(hwnd);
+}
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL register_parent_wnd_class(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Month-Cal test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND create_parent_window(void)
+{
+    HWND hwnd;
+
+    InitCommonControls();
+
+    /* flush message sequences, so we can check the new sequence by the end of function */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    hwnd = CreateWindowEx(0, "Month-Cal test parent class",
+                          "Month-Cal test parent window",
+                          WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                          WS_MAXIMIZEBOX | WS_VISIBLE,
+                          0, 0, 500, 500,
+                          GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
+
+    assert(hwnd);
+
+    /* check for message sequences */
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", TRUE);
+
+    return hwnd;
+}
+
+static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("monthcal: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND create_monthcal_control(DWORD style, HWND parent_window)
+{
+    struct subclass_info *info;
+    HWND hwnd;
+    static const INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
+
+    InitCommonControlsEx(&ic);
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    hwnd = CreateWindowEx(0,
+                    MONTHCAL_CLASS,
+                    "",
+                    style,
+                    0, 0, 300, 400,
+                    parent_window, NULL, GetModuleHandleA(NULL), NULL);
+
+    if (!hwnd)
+    {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                            (LONG_PTR)monthcal_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+
+    return hwnd;
+}
+
+
+/* Setter and Getters Tests */
+
+static void test_monthcal_color(HWND hwnd)
+{
+    int res, temp;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for color*/
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(0,0,0));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
+    expect(RGB(0,0,0), temp);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_BACKGROUND, RGB(255,255,255));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_BACKGROUND, 0);
+    expect(RGB(255,255,255), temp);
+
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(0,0,0));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
+    expect(RGB(0,0,0), temp);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_MONTHBK, RGB(255,255,255));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_MONTHBK, 0);
+    expect(RGB(255,255,255), temp);
+
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(0,0,0));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
+    expect(RGB(0,0,0), temp);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TEXT, RGB(255,255,255));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TEXT, 0);
+    expect(RGB(255,255,255), temp);
+
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(0,0,0));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
+    expect(RGB(0,0,0), temp);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLEBK, RGB(255,255,255));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLEBK, 0);
+    expect(RGB(255,255,255), temp);
+
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(0,0,0));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
+    expect(RGB(0,0,0), temp);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TITLETEXT, RGB(255,255,255));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TITLETEXT, 0);
+    expect(RGB(255,255,255), temp);
+
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(0,0,0));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
+    expect(RGB(0,0,0), temp);
+    res = SendMessage(hwnd, MCM_SETCOLOR, MCSC_TRAILINGTEXT, RGB(255,255,255));
+    expect(temp, res);
+    temp = SendMessage(hwnd, MCM_GETCOLOR, MCSC_TRAILINGTEXT, 0);
+    expect(RGB(255,255,255), temp);
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
+}
+
+static void test_monthcal_currDate(HWND hwnd)
+{
+    SYSTEMTIME st_original, st_new, st_test;
+    int res;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for current date selected */
+    st_original.wYear = 2000;
+    st_original.wMonth = 11;
+    st_original.wDay = 28;
+    st_original.wHour = 11;
+    st_original.wMinute = 59;
+    st_original.wSecond = 30;
+    st_original.wMilliseconds = 0;
+    st_original.wDayOfWeek = 0;
+
+    st_new = st_test = st_original;
+
+    /* Should not validate the time */
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
+    expect(1,res);
+
+    /* Overflow matters, check for wDay */
+    st_test.wDay += 4;
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
+    expect(0,res);
+
+    /* correct wDay before checking for wMonth */
+    st_test.wDay -= 4;
+    expect(st_original.wDay, st_test.wDay);
+
+    /* Overflow matters, check for wMonth */
+    st_test.wMonth += 4;
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_test);
+    expect(0,res);
+
+    /* checking if gets the information right, modify st_new */
+    st_new.wYear += 4;
+    st_new.wMonth += 4;
+    st_new.wDay += 4;
+    st_new.wHour += 4;
+    st_new.wMinute += 4;
+    st_new.wSecond += 4;
+
+    res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
+    expect(1, res);
+
+    /* st_new change to st_origin, above settings with overflow */
+    /* should not change the current settings */
+    expect(st_original.wYear, st_new.wYear);
+    expect(st_original.wMonth, st_new.wMonth);
+    expect(st_original.wDay, st_new.wDay);
+    expect(st_original.wHour, st_new.wHour);
+    expect(st_original.wMinute, st_new.wMinute);
+    expect(st_original.wSecond, st_new.wSecond);
+
+    /* lparam cannot be NULL */
+    res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM) NULL);
+    expect(0, res);
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
 }
 
+static void test_monthcal_firstDay(HWND hwnd)
+{
+    int res, fday, i, prev;
+    TCHAR b[128];
+    LCID lcid = LOCALE_USER_DEFAULT;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for first day of week */
+    /* check for locale first day */
+    if(GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
+        fday = atoi(b);
+        res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
+        expect(fday, res);
+        prev = fday;
+
+        /* checking for the values that actually will be stored as */
+        /* current first day when we set a new value */
+        for (i = -5; i < 12; i++){
+            res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM) i);
+            expect(prev, res);
+            res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
+            prev = res;
+
+            if (i == -1){
+                expect(MAKELONG(fday, FALSE), res);
+            }else if (i >= 7){
+                expect(MAKELONG(fday, TRUE), res);
+            }else{
+                expect(MAKELONG(i, TRUE), res);
+            }
+        }
+
+        ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_first_day_seq, "monthcal firstDay", FALSE);
+
+    }else{
+        skip("Cannot retrieve first day of the week\n");
+    }
+
+}
+
+static void test_monthcal_unicode(HWND hwnd)
+{
+    int res, temp;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for Unicode format */
+
+    /* getting the current settings */
+    temp = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
+
+    /* setting to 1, should return previous settings */
+    res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
+    expect(temp, res);
+
+    /* current setting is 1, so, should return 1 */
+    res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
+    todo_wine {expect(1, res);}
+
+    /* setting to 0, should return previous settings */
+    res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
+    todo_wine {expect(1, res);}
+
+    /* current setting is 0, so, it should return 0 */
+    res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
+    expect(0, res);
+
+    /* should return previous settings */
+    res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 1, 0);
+    expect(0, res);
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
+}
+
+static void test_monthcal_HitTest(HWND hwnd)
+{
+    MCHITTESTINFO mchit;
+    int res;
+    SYSTEMTIME st;
+
+    memset(&mchit, 0, sizeof(MCHITTESTINFO));
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    st.wYear = 2007;
+    st.wMonth = 4;
+    st.wDay = 11;
+    st.wHour = 1;
+    st.wMinute = 0;
+    st.wSecond = 0;
+    st.wMilliseconds = 0;
+    st.wDayOfWeek = 0;
+
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
+    expect(1,res);
+
+    /* (0, 0) is the top left of the control and should not be active */
+    mchit.cbSize = sizeof(MCHITTESTINFO);
+    mchit.pt.x = 0;
+    mchit.pt.y = 0;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(0, mchit.pt.x);
+    expect(0, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_NOWHERE, res);}
+
+    /* (300, 400) is the bottom right of the control and should not be active */
+    mchit.pt.x = 300;
+    mchit.pt.y = 400;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(300, mchit.pt.x);
+    expect(400, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_NOWHERE, res);}
+
+    /* (500, 500) is completely out of the control and should not be active */
+    mchit.pt.x = 500;
+    mchit.pt.y = 500;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(500, mchit.pt.x);
+    expect(500, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_NOWHERE, res);}
+
+    /* (120, 180) is in active area - calendar background */
+    mchit.pt.x = 120;
+    mchit.pt.y = 180;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(120, mchit.pt.x);
+    expect(180, mchit.pt.y);
+    expect(mchit.uHit, res);
+    expect(MCHT_CALENDARBK, res);
+
+    /* (50, 40) is in active area - previous month button */
+    mchit.pt.x = 50;
+    mchit.pt.y = 40;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(50, mchit.pt.x);
+    expect(40, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLEBTNPREV, res);}
+
+    /* (90, 40) is in active area - background section of the title */
+    mchit.pt.x = 90;
+    mchit.pt.y = 40;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(90, mchit.pt.x);
+    expect(40, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLE, res);}
+
+    /* (140, 40) is in active area - month section of the title */
+    mchit.pt.x = 140;
+    mchit.pt.y = 40;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(140, mchit.pt.x);
+    expect(40, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLEMONTH, res);}
+
+    /* (250, 40) is in active area - next month button */
+    mchit.pt.x = 250;
+    mchit.pt.y = 40;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(250, mchit.pt.x);
+    expect(40, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLEBTNNEXT, res);}
+
+    /* (70, 70) is in active area - day of the week */
+    mchit.pt.x = 70;
+    mchit.pt.y = 70;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(70, mchit.pt.x);
+    expect(70, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_CALENDARDAY, res);}
+
+    /* (70, 90) is in active area - date from prev month */
+    mchit.pt.x = 70;
+    mchit.pt.y = 90;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(70, mchit.pt.x);
+    expect(90, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_CALENDARDATEPREV, res);}
+
+#if 0
+    /* (125, 115) is in active area - date from this month */
+    mchit.pt.x = 125;
+    mchit.pt.y = 115;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(125, mchit.pt.x);
+    expect(115, mchit.pt.y);
+    expect(mchit.uHit, res);
+    expect(MCHT_CALENDARDATE, res);
+#endif
+
+    /* (80, 220) is in active area - background section of the title */
+    mchit.pt.x = 80;
+    mchit.pt.y = 220;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(80, mchit.pt.x);
+    expect(220, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLEBK, res);}
+
+    /* (140, 215) is in active area - month section of the title */
+    mchit.pt.x = 140;
+    mchit.pt.y = 215;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(140, mchit.pt.x);
+    expect(215, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLEMONTH, res);}
+
+    /* (170, 215) is in active area - year section of the title */
+    mchit.pt.x = 170;
+    mchit.pt.y = 215;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(170, mchit.pt.x);
+    expect(215, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TITLEYEAR, res);}
+
+    /* (150, 260) is in active area - date from this month */
+    mchit.pt.x = 150;
+    mchit.pt.y = 260;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(150, mchit.pt.x);
+    expect(260, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_CALENDARDATE, res);}
+
+    /* (150, 350) is in active area - date from next month */
+    mchit.pt.x = 150;
+    mchit.pt.y = 350;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(150, mchit.pt.x);
+    expect(350, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_CALENDARDATENEXT, res);}
+
+    /* (150, 370) is in active area - today link */
+    mchit.pt.x = 150;
+    mchit.pt.y = 370;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(150, mchit.pt.x);
+    expect(370, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TODAYLINK, res);}
+
+    /* (70, 370) is in active area - today link */
+    mchit.pt.x = 70;
+    mchit.pt.y = 370;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(70, mchit.pt.x);
+    expect(370, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TODAYLINK, res);}
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
+}
+
+static void test_monthcal_todaylink(HWND hwnd)
+{
+    MCHITTESTINFO mchit;
+    SYSTEMTIME st_test, st_new;
+    BOOL error = FALSE;
+    int res;
+
+    memset(&mchit, 0, sizeof(MCHITTESTINFO));
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* (70, 370) is in active area - today link */
+    mchit.cbSize = sizeof(MCHITTESTINFO);
+    mchit.pt.x = 70;
+    mchit.pt.y = 370;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect(70, mchit.pt.x);
+    expect(370, mchit.pt.y);
+    expect(mchit.uHit, res);
+    todo_wine {expect(MCHT_TODAYLINK, res);}
+    if (70 != mchit.pt.x || 370 != mchit.pt.y || mchit.uHit != res
+        || MCHT_TODAYLINK != res)
+        error = TRUE;
+
+    st_test.wDay = 1;
+    st_test.wMonth = 1;
+    st_test.wYear = 2005;
+    memset(&st_new, 0, sizeof(SYSTEMTIME));
+
+    SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
+
+    res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
+    expect(1, res);
+    expect(1, st_new.wDay);
+    expect(1, st_new.wMonth);
+    expect(2005, st_new.wYear);
+    if (1 != res || 1 != st_new.wDay || 1 != st_new.wMonth
+        || 2005 != st_new.wYear)
+        error = TRUE;
+
+    if (error) {
+        skip("cannot perform today link test\n");
+        return;
+    }
+
+    res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(70, 370));
+    expect(0, res);
+
+    memset(&st_new, 0, sizeof(SYSTEMTIME));
+    res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
+    expect(1, res);
+    expect(1, st_new.wDay);
+    expect(1, st_new.wMonth);
+    expect(2005, st_new.wYear);
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
+}
+
+static void test_monthcal_today(HWND hwnd)
+{
+    SYSTEMTIME st_test, st_new;
+    int res;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for "today" information */
+
+    /* check for overflow, should be ok */
+    st_test.wDay = 38;
+    st_test.wMonth = 38;
+
+    st_new.wDay = 27;
+    st_new.wMonth = 27;
+
+    SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
+
+    res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
+    expect(1, res);
+
+    /* st_test should not change */
+    expect(38, st_test.wDay);
+    expect(38, st_test.wMonth);
+
+    /* st_new should change, overflow does not matter */
+    expect(38, st_new.wDay);
+    expect(38, st_new.wMonth);
+
+    /* check for zero, should be ok*/
+    st_test.wDay = 0;
+    st_test.wMonth = 0;
+
+    SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
+
+    res = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st_new);
+    expect(1, res);
+
+    /* st_test should not change */
+    expect(0, st_test.wDay);
+    expect(0, st_test.wMonth);
+
+    /* st_new should change to zero*/
+    expect(0, st_new.wDay);
+    expect(0, st_new.wMonth);
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
+}
+
+static void test_monthcal_scroll(HWND hwnd)
+{
+    int res;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for scroll rate */
+    res = SendMessage(hwnd, MCM_SETMONTHDELTA, 2, 0);
+    expect(0, res);
+
+    res = SendMessage(hwnd, MCM_SETMONTHDELTA, 3, 0);
+    expect(2, res);
+    res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
+    expect(3, res);
+
+    res = SendMessage(hwnd, MCM_SETMONTHDELTA, 12, 0);
+    expect(3, res);
+    res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
+    expect(12, res);
+
+    res = SendMessage(hwnd, MCM_SETMONTHDELTA, 15, 0);
+    expect(12, res);
+    res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
+    expect(15, res);
+
+    res = SendMessage(hwnd, MCM_SETMONTHDELTA, -5, 0);
+    expect(15, res);
+    res = SendMessage(hwnd, MCM_GETMONTHDELTA, 0, 0);
+    expect(-5, res);
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
+}
+
+static void test_monthcal_monthrange(HWND hwnd)
+{
+    int res;
+    SYSTEMTIME st_visible[2], st_daystate[2];
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    st_visible[0].wYear = 0;
+    st_visible[0].wMonth = 0;
+    st_visible[0].wDay = 0;
+    st_daystate[1] = st_daystate[0] = st_visible[1] = st_visible[0];
+
+    res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
+    todo_wine {
+        expect(2, res);
+        expect(2000, st_visible[0].wYear);
+        expect(11, st_visible[0].wMonth);
+        expect(1, st_visible[0].wDay);
+        expect(2000, st_visible[1].wYear);
+        expect(12, st_visible[1].wMonth);
+        expect(31, st_visible[1].wDay);
+    }
+    res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
+    todo_wine {
+        expect(4, res);
+        expect(2000, st_daystate[0].wYear);
+        expect(10, st_daystate[0].wMonth);
+        expect(29, st_daystate[0].wDay);
+        expect(2001, st_daystate[1].wYear);
+        expect(1, st_daystate[1].wMonth);
+        expect(6, st_daystate[1].wDay);
+    }
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
+}
+
+static void test_monthcal_MaxSelDay(HWND hwnd)
+{
+    int res;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Setter and Getters for max selected days */
+    res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
+    expect(1, res);
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    expect(5, res);
+
+    res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 15, 0);
+    expect(1, res);
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    expect(15, res);
+
+    res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
+    todo_wine {expect(0, res);}
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    todo_wine {expect(15, res);}
+
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
+}
+
+
 START_TEST(monthcal)
 {
+    HWND hwnd, parent_wnd;
     test_monthcal();
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    parent_wnd = create_parent_window();
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hwnd = create_monthcal_control(WS_CHILD | WS_BORDER | WS_VISIBLE, parent_wnd);
+    assert(hwnd);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
+
+    SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
+
+    test_monthcal_color(hwnd);
+    test_monthcal_currDate(hwnd);
+    test_monthcal_firstDay(hwnd);
+    test_monthcal_unicode(hwnd);
+    test_monthcal_today(hwnd);
+    test_monthcal_scroll(hwnd);
+    test_monthcal_monthrange(hwnd);
+    test_monthcal_HitTest(hwnd);
+    test_monthcal_todaylink(hwnd);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_monthcal_parent_msgs_seq, "Destroy monthcal (parent msg)", FALSE);
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_child_msgs_seq, "Destroy monthcal (child msg)", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hwnd = create_monthcal_control(MCS_MULTISELECT, parent_wnd);
+    assert(hwnd);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
+
+    test_monthcal_MaxSelDay(hwnd);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+    ok_sequence(sequences, MONTHCAL_SEQ_INDEX, destroy_monthcal_multi_sel_style_seq, "Destroy monthcal (multi sel style)", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(parent_wnd);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, destroy_parent_seq, "Destroy parent window", FALSE);
 }
index 5b51736..2893a10 100644 (file)
@@ -111,7 +111,7 @@ static void check_reg_entries(const char *mrulist, const char**items)
     buff[0] = '\0';
     ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size);
 
-    ok(!ret && buff[0], "Checking MRU: got %ld from RegQueryValueExW\n", ret);
+    ok(!ret && buff[0], "Checking MRU: got %d from RegQueryValueExW\n", ret);
     if(ret || !buff[0]) return;
 
     ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n",
@@ -128,7 +128,7 @@ static void check_reg_entries(const char *mrulist, const char**items)
         buff[0] = '\0';
         ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size);
         ok(!ret && buff[0],
-           "Checking MRU item %d ('%c'): got %ld from RegQueryValueExW\n",
+           "Checking MRU item %d ('%c'): got %d from RegQueryValueExW\n",
            i, mrulist[i], ret);
         if(ret || !buff[0]) return;
         ok(!strcmp(buff, items[mrulist[i]-'a']),
@@ -165,37 +165,39 @@ static void test_MRUListA(void)
     if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA)
         return;
 
-#if 0 /* Create (NULL) - crashes native */
+    if (0)
+    {
+    /* Create (NULL) - crashes native */
     hMRU = pCreateMRUListA(NULL);
-#endif
+    }
 
     /* Create (size too small) */
     mruA.cbSize = sizeof(mruA) - 2;
-    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
     ok (!hMRU && !GetLastError(),
-        "CreateMRUListA(too small) expected NULL,0 got %p,%ld\n",
+        "CreateMRUListA(too small) expected NULL,0 got %p,%d\n",
         hMRU, GetLastError());
     mruA.cbSize = sizeof(mruA);
 
     /* Create (size too big) */
     mruA.cbSize = sizeof(mruA) + 2;
-    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
     ok (!hMRU && !GetLastError(),
-        "CreateMRUListA(too big) expected NULL,0 got %p,%ld\n",
+        "CreateMRUListA(too big) expected NULL,0 got %p,%d\n",
         hMRU, GetLastError());
     mruA.cbSize = sizeof(mruA);
 
     /* Create (NULL hKey) */
-    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
     ok (!hMRU && !GetLastError(),
-        "CreateMRUListA(NULL key) expected NULL,0 got %p,%ld\n",
+        "CreateMRUListA(NULL key) expected NULL,0 got %p,%d\n",
         hMRU, GetLastError());
 
     /* Create (NULL name) */
     mruA.lpszSubKey = NULL;
-    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
     ok (!hMRU && !GetLastError(),
-        "CreateMRUListA(NULL name) expected NULL,0 got %p,%ld\n",
+        "CreateMRUListA(NULL name) expected NULL,0 got %p,%d\n",
         hMRU, GetLastError());
     mruA.lpszSubKey = REG_TEST_SUBKEYA;
 
@@ -204,9 +206,9 @@ static void test_MRUListA(void)
        "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
     if (!hKey)
         return;
-    hMRU = create_mruA(hKey, MRUF_STRING_LIST, cmp_mru_strA);
+    hMRU = create_mruA(hKey, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
     ok(hMRU && !GetLastError(),
-       "CreateMRUListA(string) expected non-NULL,0 got %p,%ld\n",
+       "CreateMRUListA(string) expected non-NULL,0 got %p,%d\n",
        hMRU, GetLastError());
 
     if (hMRU)
@@ -220,38 +222,39 @@ static void test_MRUListA(void)
         SetLastError(0);
         iRet = pAddMRUStringA(NULL, checks[0]);
         ok(iRet == -1 && !GetLastError(),
-           "AddMRUStringA(NULL list) expected -1,0 got %d,%ld\n",
+           "AddMRUStringA(NULL list) expected -1,0 got %d,%d\n",
            iRet, GetLastError());
 
         /* Add (NULL string) */
-#if 0
+        if (0)
+        {
        /* Some native versions crash when passed NULL or fail to SetLastError()  */
         SetLastError(0);
         iRet = pAddMRUStringA(hMRU, NULL);
         ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
-           "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%ld\n",
+           "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%d\n",
            iRet, GetLastError());
-#endif
+        }
 
         /* Add 3 strings. Check the registry is correct after each add */
         SetLastError(0);
         iRet = pAddMRUStringA(hMRU, checks[0]);
         ok(iRet == 0 && !GetLastError(),
-           "AddMRUStringA(1) expected 0,0 got %d,%ld\n",
+           "AddMRUStringA(1) expected 0,0 got %d,%d\n",
            iRet, GetLastError());
         check_reg_entries("a", checks);
 
         SetLastError(0);
         iRet = pAddMRUStringA(hMRU, checks[1]);
         ok(iRet == 1 && !GetLastError(),
-           "AddMRUStringA(2) expected 1,0 got %d,%ld\n",
+           "AddMRUStringA(2) expected 1,0 got %d,%d\n",
            iRet, GetLastError());
         check_reg_entries("ba", checks);
 
         SetLastError(0);
         iRet = pAddMRUStringA(hMRU, checks[2]);
         ok(iRet == 2 && !GetLastError(),
-           "AddMRUStringA(2) expected 2,0 got %d,%ld\n",
+           "AddMRUStringA(2) expected 2,0 got %d,%d\n",
            iRet, GetLastError());
         check_reg_entries("cba", checks);
 
@@ -261,7 +264,7 @@ static void test_MRUListA(void)
         SetLastError(0);
         iRet = pAddMRUStringA(hMRU, checks[1]);
         ok(iRet == 1 && !GetLastError(),
-           "AddMRUStringA(re-add 1) expected 1,0 got %d,%ld\n",
+           "AddMRUStringA(re-add 1) expected 1,0 got %d,%d\n",
            iRet, GetLastError());
         check_reg_entries("bca", checks);
 
@@ -269,7 +272,7 @@ static void test_MRUListA(void)
         SetLastError(0);
         iRet = pAddMRUStringA(hMRU, checks[3]);
         ok(iRet == 0 && !GetLastError(),
-           "AddMRUStringA(add new) expected 0,0 got %d,%ld\n",
+           "AddMRUStringA(add new) expected 0,0 got %d,%d\n",
            iRet, GetLastError());
         checks[0] = checks[3];
         check_reg_entries("abc", checks);
@@ -285,8 +288,6 @@ static void test_MRUListA(void)
 START_TEST(mru)
 {
     hComctl32 = GetModuleHandleA("comctl32.dll");
-    if (!hComctl32)
-        return;
 
     delete_reg_entries();
     if (!create_reg_entries())
diff --git a/rostests/winetests/comctl32/msg.c b/rostests/winetests/comctl32/msg.c
new file mode 100644 (file)
index 0000000..2129f22
--- /dev/null
@@ -0,0 +1,251 @@
+/* Message Sequence Testing Code
+ *
+ * Copyright (C) 2007 James Hawkins
+ * Copyright (C) 2007 Lei Zhang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "msg.h"
+
+void add_message(struct msg_sequence **seq, int sequence_index,
+    const struct message *msg)
+{
+    struct msg_sequence *msg_seq = seq[sequence_index];
+
+    if (!msg_seq->sequence)
+    {
+        msg_seq->size = 10;
+        msg_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
+                                      msg_seq->size * sizeof (struct message));
+    }
+
+    if (msg_seq->count == msg_seq->size)
+    {
+        msg_seq->size *= 2;
+        msg_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
+                                        msg_seq->sequence,
+                                        msg_seq->size * sizeof (struct message));
+    }
+
+    assert(msg_seq->sequence);
+
+    msg_seq->sequence[msg_seq->count].message = msg->message;
+    msg_seq->sequence[msg_seq->count].flags = msg->flags;
+    msg_seq->sequence[msg_seq->count].wParam = msg->wParam;
+    msg_seq->sequence[msg_seq->count].lParam = msg->lParam;
+    msg_seq->sequence[msg_seq->count].id = msg->id;
+
+    msg_seq->count++;
+}
+
+void flush_sequence(struct msg_sequence **seg, int sequence_index)
+{
+    struct msg_sequence *msg_seq = seg[sequence_index];
+    HeapFree(GetProcessHeap(), 0, msg_seq->sequence);
+    msg_seq->sequence = NULL;
+    msg_seq->count = msg_seq->size = 0;
+}
+
+void flush_sequences(struct msg_sequence **seq, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+        flush_sequence(seq, i);
+}
+
+void ok_sequence_(struct msg_sequence **seq, int sequence_index,
+    const struct message *expected, const char *context, int todo,
+    const char *file, int line)
+{
+    struct msg_sequence *msg_seq = seq[sequence_index];
+    static const struct message end_of_sequence = {0, 0, 0, 0};
+    const struct message *actual, *sequence;
+    int failcount = 0;
+
+    add_message(seq, sequence_index, &end_of_sequence);
+
+    sequence = msg_seq->sequence;
+    actual = sequence;
+
+    while (expected->message && actual->message)
+    {
+        trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message);
+
+        if (expected->message == actual->message)
+        {
+            if (expected->flags & wparam)
+            {
+                if (expected->wParam != actual->wParam && todo)
+                {
+                    todo_wine
+                    {
+                        failcount++;
+                        ok_(file, line) (FALSE,
+                            "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
+                            context, expected->message, expected->wParam, actual->wParam);
+                    }
+                }
+                else
+                {
+                    ok_(file, line) (expected->wParam == actual->wParam,
+                        "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
+                        context, expected->message, expected->wParam, actual->wParam);
+                }
+            }
+
+            if (expected->flags & lparam)
+            {
+                if (expected->lParam != actual->lParam && todo)
+                {
+                    todo_wine
+                    {
+                        failcount++;
+                        ok_(file, line) (FALSE,
+                            "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
+                            context, expected->message, expected->lParam, actual->lParam);
+                    }
+                }
+                else
+                {
+                    ok_(file, line) (expected->lParam == actual->lParam,
+                        "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
+                        context, expected->message, expected->lParam, actual->lParam);
+                }
+            }
+
+            if (expected->flags & id)
+            {
+                if (expected->id != actual->id && todo)
+                {
+                    todo_wine
+                    {
+                        failcount++;
+                        ok_(file, line) (FALSE,
+                            "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n",
+                            context, expected->message, expected->id, actual->id);
+                    }
+                }
+                else
+                {
+                    ok_(file, line) (expected->id == actual->id,
+                        "%s: in msg 0x%04x expecting id 0x%x got 0x%x\n",
+                        context, expected->message, expected->id, actual->id);
+                }
+            }
+
+            if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
+            {
+                todo_wine
+                {
+                    failcount++;
+                    ok_(file, line) (FALSE,
+                        "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
+                        context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
+                }
+            }
+            else
+            {
+                ok_(file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
+                    "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n",
+                    context, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
+            }
+
+            ok_(file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
+                "%s: the msg 0x%04x should %shave been sent by BeginPaint\n",
+                context, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
+            ok_(file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
+                "%s: the msg 0x%04x should have been %s\n",
+                context, expected->message, (expected->flags & posted) ? "posted" : "sent");
+            ok_(file, line) ((expected->flags & parent) == (actual->flags & parent),
+                "%s: the msg 0x%04x was expected in %s\n",
+                context, expected->message, (expected->flags & parent) ? "parent" : "child");
+            ok_(file, line) ((expected->flags & hook) == (actual->flags & hook),
+                "%s: the msg 0x%04x should have been sent by a hook\n",
+                context, expected->message);
+            ok_(file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
+                "%s: the msg 0x%04x should have been sent by a winevent hook\n",
+                context, expected->message);
+            expected++;
+            actual++;
+        }
+        else if (expected->flags & optional)
+            expected++;
+        else if (todo)
+        {
+            failcount++;
+            todo_wine
+            {
+                ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
+                    context, expected->message, actual->message);
+            }
+
+            flush_sequence(seq, sequence_index);
+            return;
+        }
+        else
+        {
+            ok_(file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
+                context, expected->message, actual->message);
+            expected++;
+            actual++;
+        }
+    }
+
+    /* skip all optional trailing messages */
+    while (expected->message && ((expected->flags & optional)))
+        expected++;
+
+    if (todo)
+    {
+        todo_wine
+        {
+            if (expected->message || actual->message)
+            {
+                failcount++;
+                ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
+                    context, expected->message, actual->message);
+            }
+        }
+    }
+    else if (expected->message || actual->message)
+    {
+        ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n",
+            context, expected->message, actual->message);
+    }
+
+    if(todo && !failcount) /* succeeded yet marked todo */
+    {
+        todo_wine
+        {
+            ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
+        }
+    }
+
+    flush_sequence(seq, sequence_index);
+}
+
+void init_msg_sequences(struct msg_sequence **seq, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+        seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct msg_sequence));
+}
+
+START_TEST(msg)
+{
+}
diff --git a/rostests/winetests/comctl32/msg.h b/rostests/winetests/comctl32/msg.h
new file mode 100644 (file)
index 0000000..2ec3ea1
--- /dev/null
@@ -0,0 +1,73 @@
+/* Message Sequence Testing Code
+ *
+ * Copyright (C) 2007 James Hawkins
+ * Copyright (C) 2007 Lei Zhang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <windows.h>
+#include "wine/test.h"
+
+/* undocumented SWP flags - from SDK 3.1 */
+#define SWP_NOCLIENTSIZE       0x0800
+#define SWP_NOCLIENTMOVE       0x1000
+
+typedef enum
+{
+    sent = 0x1,
+    posted = 0x2,
+    parent = 0x4,
+    wparam = 0x8,
+    lparam = 0x10,
+    defwinproc = 0x20,
+    beginpaint = 0x40,
+    optional = 0x80,
+    hook = 0x100,
+    winevent_hook =0x200,
+    id = 0x400
+} msg_flags_t;
+
+struct message
+{
+    UINT message;       /* the WM_* code */
+    msg_flags_t flags;  /* message props */
+    WPARAM wParam;      /* expected value of wParam */
+    LPARAM lParam;      /* expected value of lParam */
+    UINT id;            /* id of the window */
+};
+
+struct msg_sequence
+{
+    int count;
+    int size;
+    struct message *sequence;
+};
+
+void add_message(struct msg_sequence **seq, int sequence_index,
+    const struct message *msg);
+void flush_sequence(struct msg_sequence **seg, int sequence_index);
+void flush_sequences(struct msg_sequence **seq, int n);
+
+#define ok_sequence(seq, index, exp, contx, todo) \
+        ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
+
+
+void ok_sequence_(struct msg_sequence **seq, int sequence_index,
+    const struct message *expected, const char *context, int todo,
+    const char *file, int line);
+
+void init_msg_sequences(struct msg_sequence **seq, int n);
index 35b7551..42c1e8d 100644 (file)
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
-#include "commctrl.h"
+#include "commctrl.h" 
 
 #include "wine/test.h"
 
 
-HWND hProgressParentWnd, hProgressWnd;
+static HWND hProgressParentWnd, hProgressWnd;
 static const char progressTestClass[] = "ProgressBarTestClass";
 
 
-LRESULT CALLBACK ProgressTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+/* try to make sure pending X events have been processed before continuing */
+static void flush_events(void)
+{
+    MSG msg;
+    int diff = 100;
+    DWORD time = GetTickCount() + diff;
+
+    while (diff > 0)
+    {
+        if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(10,diff), QS_ALLINPUT ) == WAIT_TIMEOUT) break;
+        while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
+        diff = time - GetTickCount();
+    }
+}
+
+static LRESULT CALLBACK ProgressTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     switch(msg) {
 
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
-
+  
     default:
         return DefWindowProcA(hWnd, msg, wParam, lParam);
     }
-
+    
     return 0L;
 }
 
@@ -52,7 +67,7 @@ static WNDPROC progress_wndproc;
 static BOOL erased;
 static RECT last_paint_rect;
 
-LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     if (msg == WM_PAINT)
     {
@@ -69,7 +84,7 @@ LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
 static void update_window(HWND hWnd)
 {
     UpdateWindow(hWnd);
-    ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n");
+    ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n");    
 }
 
 
@@ -78,29 +93,29 @@ static void init(void)
     WNDCLASSA wc;
     INITCOMMONCONTROLSEX icex;
     RECT rect;
-
+    
     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
     icex.dwICC   = ICC_PROGRESS_CLASS;
     InitCommonControlsEx(&icex);
-
+  
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
     wc.hInstance = GetModuleHandleA(NULL);
     wc.hIcon = NULL;
-    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
     wc.lpszClassName = progressTestClass;
     wc.lpfnWndProc = ProgressTestWndProc;
     RegisterClassA(&wc);
-
+    
     rect.left = 0;
     rect.top = 0;
     rect.right = 400;
     rect.bottom = 20;
     assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
-
+    
     hProgressParentWnd = CreateWindowExA(0, progressTestClass, "Progress Bar Test", WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0);
     assert(hProgressParentWnd != NULL);
@@ -110,23 +125,24 @@ static void init(void)
       0, 0, rect.right, rect.bottom, hProgressParentWnd, NULL, GetModuleHandleA(NULL), 0);
     assert(hProgressWnd != NULL);
     progress_wndproc = (WNDPROC)SetWindowLongPtr(hProgressWnd, GWLP_WNDPROC, (LPARAM)ProgressSubclassProc);
-
+    
     ShowWindow(hProgressParentWnd, SW_SHOWNORMAL);
     ok(GetUpdateRect(hProgressParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n");
-    update_window(hProgressParentWnd);
+    flush_events();
+    update_window(hProgressParentWnd);    
 }
 
 
 static void cleanup(void)
 {
     MSG msg;
-
+    
     PostMessageA(hProgressParentWnd, WM_CLOSE, 0, 0);
     while (GetMessageA(&msg,0,0,0)) {
         TranslateMessage(&msg);
         DispatchMessageA(&msg);
     }
-
+    
     UnregisterClassA(progressTestClass, GetModuleHandleA(NULL));
 }
 
@@ -147,20 +163,20 @@ static void test_redraw(void)
     /* PBM_SETPOS */
     ok(SendMessageA(hProgressWnd, PBM_SETPOS, 50, 0) == 10, "PBM_SETPOS must return the previous position\n");
     ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
-
+    
     /* PBM_DELTAPOS */
     ok(SendMessageA(hProgressWnd, PBM_DELTAPOS, 15, 0) == 50, "PBM_DELTAPOS must return the previous position\n");
     ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_DELTAPOS: The progress bar should be redrawn immediately\n");
-
+    
     /* PBM_SETPOS */
     ok(SendMessageA(hProgressWnd, PBM_SETPOS, 80, 0) == 65, "PBM_SETPOS must return the previous position\n");
     ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
-
+    
     /* PBM_STEPIT */
     ok(SendMessageA(hProgressWnd, PBM_STEPIT, 0, 0) == 80, "PBM_STEPIT must return the previous position\n");
     ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_STEPIT: The progress bar should be redrawn immediately\n");
     ok((UINT)SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0) == 100, "PBM_GETPOS returned a wrong position\n");
-
+    
     /* PBM_SETRANGE and PBM_SETRANGE32:
     Usually the progress bar doesn't repaint itself immediately. If the
     position is not in the new range, it does.
@@ -175,7 +191,7 @@ static void test_redraw(void)
     SendMessage(hProgressWnd, PBM_SETPOS, 10, 0);
     GetClientRect(hProgressWnd, &client_rect);
     ok(EqualRect(&last_paint_rect, &client_rect),
-       "last_paint_rect was { %ld, %ld, %ld, %ld } instead of { %ld, %ld, %ld, %ld }\n",
+       "last_paint_rect was { %d, %d, %d, %d } instead of { %d, %d, %d, %d }\n",
        last_paint_rect.left, last_paint_rect.top, last_paint_rect.right, last_paint_rect.bottom,
        client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
     update_window(hProgressWnd);
@@ -187,7 +203,7 @@ static void test_redraw(void)
     SendMessage(hProgressWnd, PBM_SETPOS, 0, 0);
     GetClientRect(hProgressWnd, &client_rect);
     ok(EqualRect(&last_paint_rect, &client_rect),
-       "last_paint_rect was { %ld, %ld, %ld, %ld } instead of { %ld, %ld, %ld, %ld }\n",
+       "last_paint_rect was { %d, %d, %d, %d } instead of { %d, %d, %d, %d }\n",
        last_paint_rect.left, last_paint_rect.top, last_paint_rect.right, last_paint_rect.bottom,
        client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
     update_window(hProgressWnd);
@@ -198,8 +214,8 @@ static void test_redraw(void)
 START_TEST(progress)
 {
     init();
-
+    
     test_redraw();
-
+    
     cleanup();
 }
index cbf6812..8627351 100644 (file)
@@ -17,9 +17,6 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-
 #include <windows.h>
 #include <commctrl.h>
 
@@ -39,7 +36,7 @@ static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
     }
     return 0;
 }
-
+        
 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
                                       LPARAM lparam)
 {
@@ -81,8 +78,39 @@ static void test_title(void)
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
     psp.hInstance = GetModuleHandleW(NULL);
-    psp.u.pszTemplate = "prop_page1";
-    psp.u2.pszIcon = NULL;
+    U(psp).pszTemplate = "prop_page1";
+    U2(psp).pszIcon = NULL;
+    psp.pfnDlgProc = page_dlg_proc;
+    psp.lParam = 0;
+
+    hpsp[0] = CreatePropertySheetPageA(&psp);
+
+    memset(&psh, 0, sizeof(psh));
+    psh.dwSize = sizeof(psh);
+    psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
+    psh.pszCaption = "test caption";
+    psh.nPages = 1;
+    psh.hwndParent = GetDesktopWindow();
+    U3(psh).phpage = hpsp;
+    psh.pfnCallback = sheet_callback;
+
+    hdlg = (HWND)PropertySheetA(&psh);
+    DestroyWindow(hdlg);
+}
+
+static void test_nopage(void)
+{
+    HPROPSHEETPAGE hpsp[1];
+    PROPSHEETPAGEA psp;
+    PROPSHEETHEADERA psh;
+    HWND hdlg;
+
+    memset(&psp, 0, sizeof(psp));
+    psp.dwSize = sizeof(psp);
+    psp.dwFlags = 0;
+    psp.hInstance = GetModuleHandleW(NULL);
+    U(psp).pszTemplate = "prop_page1";
+    U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = page_dlg_proc;
     psp.lParam = 0;
 
@@ -94,14 +122,18 @@ static void test_title(void)
     psh.pszCaption = "test caption";
     psh.nPages = 1;
     psh.hwndParent = GetDesktopWindow();
-    psh.u3.phpage = hpsp;
+    U3(psh).phpage = hpsp;
     psh.pfnCallback = sheet_callback;
 
     hdlg = (HWND)PropertySheetA(&psh);
+    ShowWindow(hdlg,SW_NORMAL);
+    SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
+    RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
     DestroyWindow(hdlg);
 }
 
 START_TEST(propsheet)
 {
     test_title();
+    test_nopage();
 }
diff --git a/rostests/winetests/comctl32/rebar.c b/rostests/winetests/comctl32/rebar.c
new file mode 100644 (file)
index 0000000..79da16e
--- /dev/null
@@ -0,0 +1,831 @@
+/* Unit tests for rebar.
+ *
+ * Copyright 2007 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <uxtheme.h>
+
+#include "wine/test.h"
+
+RECT height_change_notify_rect;
+static HWND hMainWnd;
+static HWND hRebar;
+
+
+#define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
+    val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \
+    val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom);
+
+#define check_rect_no_top(name, val, exp) { \
+        ok((val.bottom - val.top == exp.bottom - exp.top) && \
+            val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d), ignoring top\n", \
+            val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom); \
+    }
+
+#define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
+
+#define expect_eq(expr, value, type, format) { type ret = expr; ok((value) == ret, #expr " expected " format "  got " format "\n", (value), (ret)); }
+
+static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
+{
+    return 0;
+}
+
+static BOOL is_font_installed(const char *name)
+{
+    HDC hdc = GetDC(0);
+    BOOL ret = FALSE;
+
+    if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
+        ret = TRUE;
+
+    ReleaseDC(0, hdc);
+    return ret;
+}
+
+static void rebuild_rebar(HWND *hRebar)
+{
+    if (*hRebar)
+        DestroyWindow(*hRebar);
+
+    *hRebar = CreateWindow(REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
+        hMainWnd, (HMENU)17, GetModuleHandle(NULL), NULL);
+    SendMessageA(*hRebar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
+}
+
+static HWND build_toolbar(int nr, HWND hParent)
+{
+    TBBUTTON btns[8];
+    HWND hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE, 0, 0, 0, 0,
+        hParent, (HMENU)5, GetModuleHandle(NULL), NULL);
+    int iBitmapId = 0;
+    int i;
+
+    ok(hToolbar != NULL, "Toolbar creation problem\n");
+    ok(SendMessage(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
+    ok(SendMessage(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
+    ok(SendMessage(hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
+
+    for (i=0; i<5+nr; i++)
+    {
+        btns[i].iBitmap = i;
+        btns[i].idCommand = i;
+        btns[i].fsStyle = BTNS_BUTTON;
+        btns[i].fsState = TBSTATE_ENABLED;
+        btns[i].iString = 0;
+    }
+
+    switch (nr)
+    {
+        case 0: iBitmapId = IDB_HIST_SMALL_COLOR; break;
+        case 1: iBitmapId = IDB_VIEW_SMALL_COLOR; break;
+        case 2: iBitmapId = IDB_STD_SMALL_COLOR; break;
+    }
+    ok(SendMessage(hToolbar, TB_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGE failed\n");
+    ok(SendMessage(hToolbar, TB_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n");
+    return hToolbar;
+}
+
+static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch (msg)
+    {
+        case WM_NOTIFY:
+            {
+                NMHDR *lpnm = (NMHDR *)lParam;
+                if (lpnm->code == RBN_HEIGHTCHANGE)
+                    GetClientRect(hRebar, &height_change_notify_rect);
+            }
+            break;
+    }
+    return DefWindowProcA(hWnd, msg, wParam, lParam);
+}
+
+#if 0  /* use this to generate more tests*/
+
+static void dump_sizes(HWND hRebar)
+{
+    SIZE sz;
+    RECT r;
+    int count;
+    int i, h;
+
+    GetClientRect(hRebar, &r);
+    count = SendMessageA(hRebar, RB_GETROWCOUNT, 0, 0);
+    printf("  { {%d, %d, %d, %d}, %d, %d, {", r.left, r.top, r.right, r.bottom,
+        SendMessageA(hRebar, RB_GETBARHEIGHT, 0, 0), count);
+    if (count == 0)
+        printf("0, ");
+    for (i = 0; i < count; i++)  /* rows */
+        printf("%d, ", SendMessageA(hRebar, RB_GETROWHEIGHT, i, 0));
+    printf("}, ");
+
+    count = SendMessageA(hRebar, RB_GETBANDCOUNT, 0, 0);
+    printf("%d, {", count);
+    if (count == 0)
+        printf("{{0, 0, 0, 0}, 0, 0},");
+    for (i=0; i<count; i++)
+    {
+        REBARBANDINFO rbi;
+        rbi.cbSize = sizeof(REBARBANDINFO);
+        rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE;
+        ok(SendMessageA(hRebar, RB_GETBANDINFOA, i, (LPARAM)&rbi), "RB_GETBANDINFO failed\n");
+        ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&r), "RB_GETRECT failed\n");
+        printf("%s{ {%3d, %3d, %3d, %3d}, 0x%02x, %d}, ", (i%2==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom,
+            rbi.fStyle, rbi.cx);
+    }
+    printf("\n  }, }, \n");
+}
+
+#define check_sizes() dump_sizes(hRebar);
+#define check_sizes_todo(todomask) dump_sizes(hRebar);
+
+#else
+
+typedef struct {
+    RECT rc;
+    DWORD fStyle;
+    INT cx;
+} rbband_result_t;
+
+typedef struct {
+    RECT rcClient;
+    int cyBarHeight;
+    int nRows;
+    int cyRowHeights[50];
+    int nBands;
+    rbband_result_t bands[50];
+} rbsize_result_t;
+
+rbsize_result_t rbsize_results[] = {
+  { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
+  }, },
+  { {0, 0, 672, 4}, 4, 1, {4, }, 1, {
+    { {  0,   0, 672,   4}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 4}, 4, 1, {4, }, 2, {
+    { {  0,   0, 200,   4}, 0x00, 200}, { {200,   0, 672,   4}, 0x04, 200},
+  }, },
+  { {0, 0, 672, 30}, 30, 1, {30, }, 3, {
+    { {  0,   0, 200,  30}, 0x00, 200}, { {200,   0, 400,  30}, 0x04, 200},
+    { {400,   0, 672,  30}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 200,  34}, 0x00, 200}, { {200,   0, 400,  34}, 0x04, 200},
+    { {400,   0, 604,  34}, 0x00, 200}, { {604,   0, 672,  34}, 0x04, 68},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 200,  34}, 0x00, 200}, { {200,   0, 400,  34}, 0x04, 200},
+    { {400,   0, 604,  34}, 0x00, 200}, { {604,   0, 672,  34}, 0x04, 68},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 200,  34}, 0x00, 200}, { {202,   0, 402,  34}, 0x04, 200},
+    { {404,   0, 604,  34}, 0x00, 200}, { {606,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 70}, 70, 2, {34, 34, }, 5, {
+    { {  0,   0, 142,  34}, 0x00, 200}, { {144,   0, 557,  34}, 0x00, 200},
+    { {559,   0, 672,  34}, 0x04, 200}, { {  0,  36, 200,  70}, 0x00, 200},
+    { {202,  36, 672,  70}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 5, {
+    { {  0,   0, 167,  34}, 0x00, 200}, { {169,   0, 582,  34}, 0x00, 200},
+    { {559,   0, 759,  34}, 0x08, 200}, { {584,   0, 627,  34}, 0x00, 200},
+    { {629,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 4, {
+    { {  0,   0, 167,  34}, 0x00, 200}, { {169,   0, 582,  34}, 0x00, 200},
+    { {584,   0, 627,  34}, 0x00, 200}, { {629,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 3, {
+    { {  0,   0, 413,  34}, 0x00, 200}, { {415,   0, 615,  34}, 0x00, 200},
+    { {617,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 34}, 34, 1, {34, }, 2, {
+    { {  0,   0, 604,  34}, 0x00, 200}, { {606,   0, 672,  34}, 0x04, 66},
+  }, },
+  { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
+    { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 184,  20}, 0x00, 70},
+    { {184,   0, 424,  20}, 0x00, 240}, { {424,   0, 672,  20}, 0x00, 60},
+    { {  0,  20, 672,  40}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
+    { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 227,  20}, 0x00, 113},
+    { {227,   0, 424,  20}, 0x00, 197}, { {424,   0, 672,  20}, 0x00, 60},
+    { {  0,  20, 672,  40}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
+    { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 328,  20}, 0x00, 214},
+    { {328,   0, 511,  20}, 0x00, 183}, { {511,   0, 672,  20}, 0x00, 161},
+    { {  0,  20, 672,  40}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
+    { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 167,  20}, 0x00, 53},
+    { {167,   0, 511,  20}, 0x00, 344}, { {511,   0, 672,  20}, 0x00, 161},
+    { {  0,  20, 672,  40}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
+    { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 328,  20}, 0x00, 214},
+    { {328,   0, 511,  20}, 0x00, 183}, { {511,   0, 672,  20}, 0x00, 161},
+    { {  0,  20, 672,  40}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, {
+    { {  0,   0, 114,  20}, 0x00, 40}, { {114,   0, 328,  20}, 0x00, 214},
+    { {328,   0, 511,  20}, 0x00, 183}, { {511,   0, 672,  20}, 0x00, 161},
+    { {  0,  20, 672,  40}, 0x00, 200},
+  }, },
+  { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
+  }, },
+  { {0, 0, 672, 65}, 65, 1, {65, }, 3, {
+    { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 180,  65}, 0x40, 90},
+    { {180,   0, 672,  65}, 0x40, 90},
+  }, },
+  { {0, 0, 0, 226}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0},
+  }, },
+  { {0, 0, 65, 226}, 65, 1, {65, }, 1, {
+    { {  0,   0, 226,  65}, 0x40, 90},
+  }, },
+  { {0, 0, 65, 226}, 65, 1, {65, }, 2, {
+    { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 226,  65}, 0x40, 90},
+  }, },
+  { {0, 0, 65, 226}, 65, 1, {65, }, 3, {
+    { {  0,   0,  90,  65}, 0x40, 90}, { { 90,   0, 163,  65}, 0x40, 90},
+    { {163,   0, 226,  65}, 0x40, 90},
+  }, },
+};
+
+static int rbsize_numtests = 0;
+
+#define check_sizes_todo(todomask) { \
+        RECT rc; \
+        REBARBANDINFO rbi; \
+        int count, i/*, mask=(todomask)*/; \
+        rbsize_result_t *res = &rbsize_results[rbsize_numtests]; \
+        assert(rbsize_numtests < sizeof(rbsize_results)/sizeof(rbsize_results[0])); \
+        GetClientRect(hRebar, &rc); \
+        check_rect("client", rc, res->rcClient); \
+        count = SendMessage(hRebar, RB_GETROWCOUNT, 0, 0); \
+        compare(count, res->nRows, "%d"); \
+        for (i=0; i<min(count, res->nRows); i++) { \
+            int height = SendMessageA(hRebar, RB_GETROWHEIGHT, 0, 0);\
+            ok(height == res->cyRowHeights[i], "Height mismatch for row %d - %d vs %d\n", i, res->cyRowHeights[i], height); \
+        } \
+        count = SendMessage(hRebar, RB_GETBANDCOUNT, 0, 0); \
+        compare(count, res->nBands, "%d"); \
+        for (i=0; i<min(count, res->nBands); i++) { \
+            ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_ITEMRECT\n"); \
+            if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \
+                check_rect("band", rc, res->bands[i].rc); \
+            rbi.cbSize = sizeof(REBARBANDINFO); \
+            rbi.fMask = RBBIM_STYLE | RBBIM_SIZE; \
+            ok(SendMessageA(hRebar, RB_GETBANDINFO,  i, (LPARAM)&rbi) == 1, "RB_GETBANDINFO\n"); \
+            compare(rbi.fStyle, res->bands[i].fStyle, "%x"); \
+            compare(rbi.cx, res->bands[i].cx, "%d"); \
+        } \
+        rbsize_numtests++; \
+    }
+
+#define check_sizes() check_sizes_todo(0)
+
+#endif
+
+static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal)
+{
+    CHAR buffer[MAX_PATH];
+    REBARBANDINFO rbi;
+
+    if (lpszText != NULL)
+        strcpy(buffer, lpszText);
+    rbi.cbSize = sizeof(rbi);
+    rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT;
+    rbi.cx = cx;
+    rbi.cxMinChild = cxMinChild;
+    rbi.cxIdeal = cxIdeal;
+    rbi.cyMinChild = 20;
+    rbi.hwndChild = build_toolbar(1, hRebar);
+    rbi.lpText = (lpszText ? buffer : NULL);
+    SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+}
+
+static void layout_test(void)
+{
+    HWND hRebar = NULL;
+    REBARBANDINFO rbi;
+
+    rebuild_rebar(&hRebar);
+    check_sizes();
+    rbi.cbSize = sizeof(rbi);
+    rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
+    rbi.cx = 200;
+    rbi.cxMinChild = 100;
+    rbi.cyMinChild = 30;
+    rbi.hwndChild = NULL;
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fMask |= RBBIM_STYLE;
+    rbi.fStyle = RBBS_CHILDEDGE;
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fStyle = 0;
+    rbi.cx = 200;
+    rbi.cxMinChild = 30;
+    rbi.cyMinChild = 30;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fStyle = RBBS_CHILDEDGE;
+    rbi.cx = 68;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_BANDBORDERS);
+    check_sizes();      /* a style change won't start a relayout */
+    rbi.fMask = RBBIM_SIZE;
+    rbi.cx = 66;
+    SendMessageA(hRebar, RB_SETBANDINFO, 3, (LPARAM)&rbi);
+    check_sizes();      /* here it will be relayouted */
+
+    /* this will force a new row */
+    rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
+    rbi.cx = 200;
+    rbi.cxMinChild = 400;
+    rbi.cyMinChild = 30;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, 1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.fMask = RBBIM_STYLE;
+    rbi.fStyle = RBBS_HIDDEN;
+    SendMessageA(hRebar, RB_SETBANDINFO, 2, (LPARAM)&rbi);
+    check_sizes();
+
+    SendMessageA(hRebar, RB_DELETEBAND, 2, 0);
+    check_sizes();
+    SendMessageA(hRebar, RB_DELETEBAND, 0, 0);
+    check_sizes();
+    SendMessageA(hRebar, RB_DELETEBAND, 1, 0);
+    check_sizes();
+
+    rebuild_rebar(&hRebar);
+    add_band_w(hRebar, "ABC",     70,  40, 100);
+    add_band_w(hRebar, NULL,      40,  70, 100);
+    add_band_w(hRebar, NULL,     170, 240, 100);
+    add_band_w(hRebar, "MMMMMMM", 60,  60, 100);
+    add_band_w(hRebar, NULL,     200, 200, 100);
+    check_sizes();
+    SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE);
+    check_sizes();
+    SendMessageA(hRebar, RB_MAXIMIZEBAND, 1, TRUE);
+    check_sizes();
+    SendMessageA(hRebar, RB_MAXIMIZEBAND, 2, FALSE);
+    check_sizes();
+    SendMessageA(hRebar, RB_MINIMIZEBAND, 2, 0);
+    check_sizes();
+    SendMessageA(hRebar, RB_MINIMIZEBAND, 0, 0);
+    check_sizes();
+
+    /* VARHEIGHT resizing test on a horizontal rebar */
+    rebuild_rebar(&hRebar);
+    SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
+    check_sizes();
+    rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
+    rbi.fStyle = RBBS_VARIABLEHEIGHT;
+    rbi.cxMinChild = 50;
+    rbi.cyMinChild = 10;
+    rbi.cyIntegral = 11;
+    rbi.cyChild = 70;
+    rbi.cyMaxChild = 200;
+    rbi.cx = 90;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+
+    rbi.cyChild = 50;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+
+    rbi.cyMinChild = 40;
+    rbi.cyChild = 50;
+    rbi.cyIntegral = 5;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    /* VARHEIGHT resizing on a vertical rebar */
+    rebuild_rebar(&hRebar);
+    SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE);
+    check_sizes();
+    rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
+    rbi.fStyle = RBBS_VARIABLEHEIGHT;
+    rbi.cxMinChild = 50;
+    rbi.cyMinChild = 10;
+    rbi.cyIntegral = 11;
+    rbi.cyChild = 70;
+    rbi.cyMaxChild = 90;
+    rbi.cx = 90;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.cyChild = 50;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    rbi.cyMinChild = 40;
+    rbi.cyChild = 50;
+    rbi.cyIntegral = 5;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    DestroyWindow(hRebar);
+}
+
+#if 0       /* use this to generate more tests */
+
+static void dump_client(HWND hRebar)
+{
+    RECT r;
+    BOOL notify;
+    GetWindowRect(hRebar, &r);
+    MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2);
+    if (height_change_notify_rect.top != -1)
+    {
+        RECT rcClient;
+        GetClientRect(hRebar, &rcClient);
+        assert(EqualRect(&rcClient, &height_change_notify_rect));
+        notify = TRUE;
+    }
+    else
+        notify = FALSE;
+    printf("    {{%d, %d, %d, %d}, %d, %s},\n", r.left, r.top, r.right, r.bottom, SendMessage(hRebar, RB_GETROWCOUNT, 0, 0),
+        notify ? "TRUE" : "FALSE");
+    SetRect(&height_change_notify_rect, -1, -1, -1, -1);
+}
+
+#define comment(fmt, arg1) printf("/* " fmt " */\n", arg1);
+#define check_client() dump_client(hRebar)
+
+#else
+
+typedef struct {
+    RECT rc;
+    INT iNumRows;
+    BOOL heightNotify;
+} rbresize_test_result_t;
+
+rbresize_test_result_t resize_results[] = {
+/* style 00000001 */
+    {{0, 2, 672, 2}, 0, FALSE},
+    {{0, 2, 672, 22}, 1, TRUE},
+    {{0, 2, 672, 22}, 1, FALSE},
+    {{0, 2, 672, 22}, 1, FALSE},
+    {{0, 2, 672, 22}, 1, FALSE},
+    {{0, 2, 672, 22}, 0, FALSE},
+/* style 00000041 */
+    {{0, 0, 672, 0}, 0, FALSE},
+    {{0, 0, 672, 20}, 1, TRUE},
+    {{0, 0, 672, 20}, 1, FALSE},
+    {{0, 0, 672, 20}, 1, FALSE},
+    {{0, 0, 672, 20}, 1, FALSE},
+    {{0, 0, 672, 20}, 0, FALSE},
+/* style 00000003 */
+    {{0, 226, 672, 226}, 0, FALSE},
+    {{0, 206, 672, 226}, 1, TRUE},
+    {{0, 206, 672, 226}, 1, FALSE},
+    {{0, 206, 672, 226}, 1, FALSE},
+    {{0, 206, 672, 226}, 1, FALSE},
+    {{0, 206, 672, 226}, 0, FALSE},
+/* style 00000043 */
+    {{0, 226, 672, 226}, 0, FALSE},
+    {{0, 206, 672, 226}, 1, TRUE},
+    {{0, 206, 672, 226}, 1, FALSE},
+    {{0, 206, 672, 226}, 1, FALSE},
+    {{0, 206, 672, 226}, 1, FALSE},
+    {{0, 206, 672, 226}, 0, FALSE},
+/* style 00000080 */
+    {{2, 0, 2, 226}, 0, FALSE},
+    {{2, 0, 22, 226}, 1, TRUE},
+    {{2, 0, 22, 226}, 1, FALSE},
+    {{2, 0, 22, 226}, 1, FALSE},
+    {{2, 0, 22, 226}, 1, FALSE},
+    {{2, 0, 22, 226}, 0, FALSE},
+/* style 00000083 */
+    {{672, 0, 672, 226}, 0, FALSE},
+    {{652, 0, 672, 226}, 1, TRUE},
+    {{652, 0, 672, 226}, 1, FALSE},
+    {{652, 0, 672, 226}, 1, FALSE},
+    {{652, 0, 672, 226}, 1, FALSE},
+    {{652, 0, 672, 226}, 0, FALSE},
+/* style 00000008 */
+    {{10, 11, 510, 11}, 0, FALSE},
+    {{10, 15, 510, 35}, 1, TRUE},
+    {{10, 17, 510, 37}, 1, FALSE},
+    {{10, 14, 110, 54}, 2, TRUE},
+    {{0, 4, 0, 44}, 2, FALSE},
+    {{0, 6, 0, 46}, 2, FALSE},
+    {{0, 8, 0, 48}, 2, FALSE},
+    {{0, 12, 0, 32}, 1, TRUE},
+    {{0, 4, 100, 24}, 0, FALSE},
+/* style 00000048 */
+    {{10, 5, 510, 5}, 0, FALSE},
+    {{10, 5, 510, 25}, 1, TRUE},
+    {{10, 5, 510, 25}, 1, FALSE},
+    {{10, 10, 110, 50}, 2, TRUE},
+    {{0, 0, 0, 40}, 2, FALSE},
+    {{0, 0, 0, 40}, 2, FALSE},
+    {{0, 0, 0, 40}, 2, FALSE},
+    {{0, 0, 0, 20}, 1, TRUE},
+    {{0, 0, 100, 20}, 0, FALSE},
+/* style 00000004 */
+    {{10, 5, 510, 20}, 0, FALSE},
+    {{10, 5, 510, 20}, 1, TRUE},
+    {{10, 10, 110, 110}, 2, TRUE},
+    {{0, 0, 0, 0}, 2, FALSE},
+    {{0, 0, 0, 0}, 2, FALSE},
+    {{0, 0, 0, 0}, 2, FALSE},
+    {{0, 0, 0, 0}, 1, TRUE},
+    {{0, 0, 100, 100}, 0, FALSE},
+/* style 00000002 */
+    {{0, 5, 672, 5}, 0, FALSE},
+    {{0, 5, 672, 25}, 1, TRUE},
+    {{0, 10, 672, 30}, 1, FALSE},
+    {{0, 0, 672, 20}, 1, FALSE},
+    {{0, 0, 672, 20}, 1, FALSE},
+    {{0, 0, 672, 20}, 0, FALSE},
+/* style 00000082 */
+    {{10, 0, 10, 226}, 0, FALSE},
+    {{10, 0, 30, 226}, 1, TRUE},
+    {{10, 0, 30, 226}, 1, FALSE},
+    {{0, 0, 20, 226}, 1, FALSE},
+    {{0, 0, 20, 226}, 1, FALSE},
+    {{0, 0, 20, 226}, 0, FALSE},
+/* style 00800001 */
+    {{-2, 0, 674, 4}, 0, FALSE},
+    {{-2, 0, 674, 24}, 1, TRUE},
+    {{-2, 0, 674, 24}, 1, FALSE},
+    {{-2, 0, 674, 24}, 1, FALSE},
+    {{-2, 0, 674, 24}, 1, FALSE},
+    {{-2, 0, 674, 24}, 0, FALSE},
+/* style 00800048 */
+    {{10, 5, 510, 9}, 0, FALSE},
+    {{10, 5, 510, 29}, 1, TRUE},
+    {{10, 5, 510, 29}, 1, FALSE},
+    {{10, 10, 110, 54}, 2, TRUE},
+    {{0, 0, 0, 44}, 2, FALSE},
+    {{0, 0, 0, 44}, 2, FALSE},
+    {{0, 0, 0, 44}, 2, FALSE},
+    {{0, 0, 0, 24}, 1, TRUE},
+    {{0, 0, 100, 24}, 0, FALSE},
+/* style 00800004 */
+    {{10, 5, 510, 20}, 0, FALSE},
+    {{10, 5, 510, 20}, 1, TRUE},
+    {{10, 10, 110, 110}, 2, TRUE},
+    {{0, 0, 0, 0}, 2, FALSE},
+    {{0, 0, 0, 0}, 2, FALSE},
+    {{0, 0, 0, 0}, 2, FALSE},
+    {{0, 0, 0, 0}, 1, TRUE},
+    {{0, 0, 100, 100}, 0, FALSE},
+/* style 00800002 */
+    {{-2, 5, 674, 9}, 0, FALSE},
+    {{-2, 5, 674, 29}, 1, TRUE},
+    {{-2, 10, 674, 34}, 1, FALSE},
+    {{-2, 0, 674, 24}, 1, FALSE},
+    {{-2, 0, 674, 24}, 1, FALSE},
+    {{-2, 0, 674, 24}, 0, FALSE},
+};
+
+static int resize_numtests = 0;
+
+#define comment(fmt, arg1)
+#define check_client() { \
+        RECT r; \
+        rbresize_test_result_t *res = &resize_results[resize_numtests++]; \
+        assert(resize_numtests <= sizeof(resize_results)/sizeof(resize_results[0])); \
+        GetWindowRect(hRebar, &r); \
+        MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); \
+        if ((dwStyles[i] & (CCS_NOPARENTALIGN|CCS_NODIVIDER)) == CCS_NOPARENTALIGN) {\
+            check_rect_no_top("client", r, res->rc); /* the top coordinate changes after every layout and is very implementation-dependent */ \
+        } else { \
+            check_rect("client", r, res->rc); \
+        } \
+        expect_eq((int)SendMessage(hRebar, RB_GETROWCOUNT, 0, 0), res->iNumRows, int, "%d"); \
+        if (res->heightNotify) { \
+            RECT rcClient; \
+            GetClientRect(hRebar, &rcClient); \
+            check_rect("notify", height_change_notify_rect, rcClient); \
+        } else ok(height_change_notify_rect.top == -1, "Unexpected RBN_HEIGHTCHANGE received\n"); \
+        SetRect(&height_change_notify_rect, -1, -1, -1, -1); \
+    }
+
+#endif
+
+static void resize_test(void)
+{
+    DWORD dwStyles[] = {CCS_TOP, CCS_TOP | CCS_NODIVIDER, CCS_BOTTOM, CCS_BOTTOM | CCS_NODIVIDER, CCS_VERT, CCS_RIGHT,
+        CCS_NOPARENTALIGN, CCS_NOPARENTALIGN | CCS_NODIVIDER, CCS_NORESIZE, CCS_NOMOVEY, CCS_NOMOVEY | CCS_VERT,
+        CCS_TOP | WS_BORDER, CCS_NOPARENTALIGN | CCS_NODIVIDER | WS_BORDER, CCS_NORESIZE | WS_BORDER,
+        CCS_NOMOVEY | WS_BORDER};
+
+    const int styles_count = sizeof(dwStyles) / sizeof(dwStyles[0]);
+    int i;
+
+    for (i = 0; i < styles_count; i++)
+    {
+        comment("style %08x", dwStyles[i]);
+        SetRect(&height_change_notify_rect, -1, -1, -1, -1);
+        hRebar = CreateWindow(REBARCLASSNAME, "A", dwStyles[i] | WS_CHILD | WS_VISIBLE, 10, 5, 500, 15, hMainWnd, NULL, GetModuleHandle(NULL), 0);
+        check_client();
+        add_band_w(hRebar, NULL, 70, 100, 0);
+        if (dwStyles[i] & CCS_NOPARENTALIGN)  /* the window drifts downward for CCS_NOPARENTALIGN without CCS_NODIVIDER */
+            check_client();
+        add_band_w(hRebar, NULL, 70, 100, 0);
+        check_client();
+        MoveWindow(hRebar, 10, 10, 100, 100, TRUE);
+        check_client();
+        MoveWindow(hRebar, 0, 0, 0, 0, TRUE);
+        check_client();
+        /* try to fool the rebar by sending invalid width/height - won't work */
+        if (dwStyles[i] & (CCS_NORESIZE | CCS_NOPARENTALIGN))
+        {
+            WINDOWPOS pos;
+            pos.hwnd = hRebar;
+            pos.hwndInsertAfter = NULL;
+            pos.cx = 500;
+            pos.cy = 500;
+            pos.x = 10;
+            pos.y = 10;
+            pos.flags = 0;
+            SendMessage(hRebar, WM_WINDOWPOSCHANGING, 0, (LPARAM)&pos);
+            SendMessage(hRebar, WM_WINDOWPOSCHANGED, 0, (LPARAM)&pos);
+            check_client();
+            SendMessage(hRebar, WM_SIZE, SIZE_RESTORED, MAKELONG(500, 500));
+            check_client();
+        }
+        SendMessage(hRebar, RB_DELETEBAND, 0, 0);
+        check_client();
+        SendMessage(hRebar, RB_DELETEBAND, 0, 0);
+        MoveWindow(hRebar, 0, 0, 100, 100, TRUE);
+        check_client();
+        DestroyWindow(hRebar);
+    }
+}
+
+static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore,
+    COLORREF clrBack, LPCSTR lpText, int iImage, HWND hwndChild,
+    INT cxMinChild, INT cyMinChild, INT cx, HBITMAP hbmBack, INT wID,
+    INT cyChild, INT cyMaxChild, INT cyIntegral, INT cxIdeal, LPARAM lParam,
+    INT cxHeader)
+{
+    CHAR buf[MAX_PATH] = "abc";
+    REBARBANDINFO rb;
+
+    memset(&rb, 0xdd, sizeof(rb));
+    rb.cbSize = sizeof(rb);
+    rb.fMask = RBBIM_BACKGROUND | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_COLORS
+        | RBBIM_HEADERSIZE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_IMAGE | RBBIM_LPARAM
+        | RBBIM_SIZE | RBBIM_STYLE | RBBIM_TEXT;
+    rb.lpText = buf;
+    rb.cch = MAX_PATH;
+    ok(SendMessageA(hRebar, RB_GETBANDINFOA, uBand, (LPARAM)&rb), "RB_GETBANDINFO failed\n");
+    expect_eq(rb.fStyle, fStyle, int, "%x");
+    todo_wine expect_eq(rb.clrFore, clrFore, COLORREF, "%x");
+    todo_wine expect_eq(rb.clrBack, clrBack, unsigned, "%x");
+    expect_eq(strcmp(rb.lpText, lpText), 0, int, "%d");
+    expect_eq(rb.iImage, iImage, int, "%x");
+    expect_eq(rb.hwndChild, hwndChild, HWND, "%p");
+    expect_eq(rb.cxMinChild, cxMinChild, int, "%d");
+    expect_eq(rb.cyMinChild, cyMinChild, int, "%d");
+    expect_eq(rb.cx, cx, int, "%d");
+    expect_eq(rb.hbmBack, hbmBack, HBITMAP, "%p");
+    expect_eq(rb.wID, wID, int, "%d");
+    /* the values of cyChild, cyMaxChild and cyIntegral can't be read unless the band is RBBS_VARIABLEHEIGHT */
+    expect_eq(rb.cyChild, cyChild, int, "%x");
+    expect_eq(rb.cyMaxChild, cyMaxChild, int, "%x");
+    expect_eq(rb.cyIntegral, cyIntegral, int, "%x");
+    expect_eq(rb.cxIdeal, cxIdeal, int, "%d");
+    expect_eq(rb.lParam, lParam, LPARAM, "%ld");
+    expect_eq(rb.cxHeader, cxHeader, int, "%d");
+}
+
+static void bandinfo_test(void)
+{
+    REBARBANDINFOA rb;
+    CHAR szABC[] = "ABC";
+    CHAR szABCD[] = "ABCD";
+
+    rebuild_rebar(&hRebar);
+    rb.cbSize = sizeof(REBARBANDINFO);
+    rb.fMask = 0;
+    ok(SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0);
+
+    rb.fMask = RBBIM_CHILDSIZE;
+    rb.cxMinChild = 15;
+    rb.cyMinChild = 20;
+    rb.cyChild = 30;
+    rb.cyMaxChild = 20;
+    rb.cyIntegral = 10;
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0);
+
+    rb.fMask = RBBIM_TEXT;
+    rb.lpText = szABC;
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 35);
+
+    rb.cbSize = sizeof(REBARBANDINFO);
+    rb.fMask = 0;
+    ok(SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9);
+    expect_band_content(0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 40);
+
+    rb.fMask = RBBIM_HEADERSIZE;
+    rb.cxHeader = 50;
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50);
+
+    rb.cxHeader = 5;
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5);
+
+    rb.fMask = RBBIM_TEXT;
+    rb.lpText = szABCD;
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5);
+    rb.fMask = RBBIM_STYLE | RBBIM_TEXT;
+    rb.fStyle = RBBS_VARIABLEHEIGHT;
+    rb.lpText = szABC;
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_INSERTBAND failed\n");
+    expect_band_content(0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 40);
+
+    DestroyWindow(hRebar);
+}
+
+START_TEST(rebar)
+{
+    INITCOMMONCONTROLSEX icc;
+    WNDCLASSA wc;
+    MSG msg;
+    RECT rc;
+
+    icc.dwSize = sizeof(icc);
+    icc.dwICC = ICC_COOL_CLASSES;
+    InitCommonControlsEx(&icc);
+
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "MyTestWnd";
+    wc.lpfnWndProc = MyWndProc;
+    RegisterClassA(&wc);
+    hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
+      CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
+      226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
+      NULL, NULL, GetModuleHandleA(NULL), 0);
+    GetClientRect(hMainWnd, &rc);
+    ShowWindow(hMainWnd, SW_SHOW);
+
+    bandinfo_test();
+
+    if(is_font_installed("System") && is_font_installed("Tahoma"))
+    {
+        layout_test();
+        resize_test();
+    } else
+        skip("Missing System or Tahoma font\n");
+
+    PostQuitMessage(0);
+    while(GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+    DestroyWindow(hMainWnd);
+}
diff --git a/rostests/winetests/comctl32/resources.h b/rostests/winetests/comctl32/resources.h
new file mode 100644 (file)
index 0000000..c99633d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Resource IDs
+ *
+ * Copyright 2006 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_COMCTL32_TEST_RESOURCES_H
+#define __WINE_COMCTL32_TEST_RESOURCES_H
+
+#define IDB_BITMAP_128x15       10
+#define IDB_BITMAP_80x15        11
+
+#define IDS_TBADD1      16
+#define IDS_TBADD2      17
+#define IDS_TBADD3      18
+#define IDS_TBADD4      19
+#define IDS_TBADD5      20
+#define IDS_TBADD7      22
+
+#endif  /* __WINE_COMCTL32_TEST_RESOURCES_H */
similarity index 68%
rename from rostests/winetests/comctl32/propsheet.rc
rename to rostests/winetests/comctl32/rsrc.rc
index 2296141..bf195b6 100644 (file)
@@ -1,6 +1,7 @@
-/* Resources for the unit test suite for property sheet control.
+/* Resources for the common control unit test suite.
  *
  * Copyright 2006 Huw Davies
+ * Copyright 2006 Mikolaj Zalewski
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,6 +20,7 @@
 
 #include "windef.h"
 #include "winuser.h"
+#include "resources.h"
 
 PROP_PAGE1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
 STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
@@ -27,3 +29,19 @@ FONT 8, "MS Shell Dlg"
 {
  LTEXT "Test", -1, 10, 6, 100, 8
 }
+
+STRINGTABLE 
+{
+    IDS_TBADD1           "abc"
+    IDS_TBADD2           "|p|q|r"
+    IDS_TBADD3           "*p*q*"
+    IDS_TBADD4           "#p#q##"
+    IDS_TBADD5           "|p||q|r|"
+    IDS_TBADD7           "abracadabra"
+}
+
+/* @makedep: bmp128x15.bmp */
+IDB_BITMAP_128x15 BITMAP bmp128x15.bmp
+
+/* @makedep: bmp80x15.bmp */
+IDB_BITMAP_80x15 BITMAP bmp80x15.bmp
diff --git a/rostests/winetests/comctl32/status.c b/rostests/winetests/comctl32/status.c
new file mode 100644 (file)
index 0000000..4e643c1
--- /dev/null
@@ -0,0 +1,196 @@
+/* Unit test suite for status control.
+ *
+ * Copyright 2007 Google (Lei Zhang)
+ * Copyright 2007 Alex Arazi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+#define expect(expected,got) ok (expected == got,"Expected %d, got %d\n",expected,got);
+
+static HINSTANCE hinst;
+
+static HWND create_status_control(DWORD style, DWORD exstyle)
+{
+    HWND hWndStatus;
+
+    /* make the control */
+    hWndStatus = CreateWindowEx(exstyle, STATUSCLASSNAME, NULL, style,
+        /* placement */
+        0, 0, 300, 20,
+        /* parent, etc */
+        NULL, NULL, hinst, NULL);
+    assert (hWndStatus);
+    return hWndStatus;
+}
+
+static void test_status_control(void)
+{
+    HWND hWndStatus;
+    int r;
+    int nParts[] = {50, 150, -1};
+    int checkParts[] = {0, 0, 0};
+    int borders[] = {0, 0, 0};
+    RECT rc;
+    CHAR charArray[20];
+    HICON hIcon;
+
+    hWndStatus = create_status_control(WS_VISIBLE, 0);
+
+    /* Divide into parts and set text */
+    r = SendMessage(hWndStatus, SB_SETPARTS, 3, (long)nParts);
+    expect(TRUE,r);
+    r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First");
+    expect(TRUE,r);
+    r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"Second");
+    expect(TRUE,r);
+    r = SendMessage(hWndStatus, SB_SETTEXT, 2, (LPARAM)"Third");
+    expect(TRUE,r);
+
+    /* Get RECT Information */
+    r = SendMessage(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc);
+    expect(TRUE,r);
+    expect(2,rc.top);
+    /* The rc.bottom test is system dependent
+    expect(22,rc.bottom); */
+    expect(0,rc.left);
+    expect(50,rc.right);
+    r = SendMessage(hWndStatus, SB_GETRECT, -1, (LPARAM)&rc);
+    expect(FALSE,r);
+    r = SendMessage(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc);
+    expect(FALSE,r);
+    /* Get text length and text */
+    r = SendMessage(hWndStatus, SB_GETTEXTLENGTH, 2, 0);
+    expect(5,LOWORD(r));
+    expect(0,HIWORD(r));
+    r = SendMessage(hWndStatus, SB_GETTEXT, 2, (LPARAM) charArray);
+    ok(strcmp(charArray,"Third") == 0, "Expected Third, got %s\n", charArray);
+    expect(5,LOWORD(r));
+    expect(0,HIWORD(r));
+
+    /* Get parts and borders */
+    r = SendMessage(hWndStatus, SB_GETPARTS, 3, (long)checkParts);
+    ok(r == 3, "Expected 3, got %d\n", r);
+    expect(50,checkParts[0]);
+    expect(150,checkParts[1]);
+    expect(-1,checkParts[2]);
+    r = SendMessage(hWndStatus, SB_GETBORDERS, 0, (long)borders);
+    ok(r == TRUE, "Expected TRUE, got %d\n", r);
+    expect(0,borders[0]);
+    expect(2,borders[1]);
+    expect(2,borders[2]);
+
+    /* Test resetting text with different characters */
+    r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First@Again");
+    expect(TRUE,r);
+    r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"InvalidChars\\7\7");
+        expect(TRUE,r);
+    r = SendMessage(hWndStatus, SB_SETTEXT, 2, (LPARAM)"InvalidChars\\n\n");
+        expect(TRUE,r);
+
+    /* Get text again */
+    r = SendMessage(hWndStatus, SB_GETTEXT, 0, (LPARAM) charArray);
+    ok(strcmp(charArray,"First@Again") == 0, "Expected First@Again, got %s\n", charArray);
+    expect(11,LOWORD(r));
+    expect(0,HIWORD(r));
+    r = SendMessage(hWndStatus, SB_GETTEXT, 1, (LPARAM) charArray);
+    todo_wine
+    {
+        ok(strcmp(charArray,"InvalidChars\\7 ") == 0, "Expected InvalidChars\\7 , got %s\n", charArray);
+    }
+    expect(15,LOWORD(r));
+    expect(0,HIWORD(r));
+    r = SendMessage(hWndStatus, SB_GETTEXT, 2, (LPARAM) charArray);
+    todo_wine
+    {
+        ok(strcmp(charArray,"InvalidChars\\n ") == 0, "Expected InvalidChars\\n , got %s\n", charArray);
+    }
+    expect(15,LOWORD(r));
+    expect(0,HIWORD(r));
+
+    /* Set background color */
+    r = SendMessage(hWndStatus, SB_SETBKCOLOR , 0, RGB(255,0,0));
+    expect(CLR_DEFAULT,r);
+    r = SendMessage(hWndStatus, SB_SETBKCOLOR , 0, CLR_DEFAULT);
+    expect(RGB(255,0,0),r);
+
+    /* Add an icon to the status bar */
+    hIcon = LoadIcon(NULL, IDI_QUESTION);
+    r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) NULL);
+    ok(r != 0, "Expected non-zero, got %d\n", r);
+    r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) hIcon);
+    ok(r != 0, "Expected non-zero, got %d\n", r);
+    r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) NULL);
+    ok(r != 0, "Expected non-zero, got %d\n", r);
+
+    /* Set the Unicode format */
+    r = SendMessage(hWndStatus, SB_SETUNICODEFORMAT, FALSE, 0);
+    r = SendMessage(hWndStatus, SB_GETUNICODEFORMAT, 0, 0);
+    expect(FALSE,r);
+    r = SendMessage(hWndStatus, SB_SETUNICODEFORMAT, TRUE, 0);
+    expect(FALSE,r);
+    r = SendMessage(hWndStatus, SB_GETUNICODEFORMAT, 0, 0);
+    expect(TRUE,r);
+
+    /* Reset number of parts */
+    r = SendMessage(hWndStatus, SB_SETPARTS, 2, (long)nParts);
+    expect(TRUE,r);
+
+    /* Set the minimum height and get rectangle information again */
+    SendMessage(hWndStatus, SB_SETMINHEIGHT, 50, (LPARAM) 0);
+    r = SendMessage(hWndStatus, WM_SIZE, 0, (LPARAM) 0);
+    expect(0,r);
+    r = SendMessage(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc);
+    expect(TRUE,r);
+    expect(2,rc.top);
+    /* The rc.bottom test is system dependent
+    expect(22,rc.bottom); */
+    expect(0,rc.left);
+    expect(50,rc.right);
+    r = SendMessage(hWndStatus, SB_GETRECT, -1, (LPARAM)&rc);
+    expect(FALSE,r);
+    r = SendMessage(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc);
+    expect(FALSE,r);
+
+    /* Set the ToolTip text */
+    todo_wine
+    {
+        SendMessage(hWndStatus, SB_SETTIPTEXT, 0,(LPARAM) "Tooltip Text");
+        SendMessage(hWndStatus, SB_GETTIPTEXT, MAKEWPARAM (0, 20),(LPARAM) charArray);
+        ok(strcmp(charArray,"Tooltip Text") == 0, "Expected Tooltip Text, got %s\n", charArray);
+    }
+
+    /* Make simple */
+    SendMessage(hWndStatus, SB_SIMPLE, TRUE, 0);
+    r = SendMessage(hWndStatus, SB_ISSIMPLE, 0, 0);
+    expect(TRUE,r);
+
+    DestroyWindow(hWndStatus);
+}
+
+START_TEST(status)
+{
+    hinst = GetModuleHandleA(NULL);
+
+    InitCommonControls();
+
+    test_status_control();
+}
index 937ec1b..9c879e3 100644 (file)
@@ -156,7 +156,7 @@ static void ok_sequence(const struct message *expected, const char *context)
             "%s: the procnum %d was expected, but got procnum %d instead\n",
             context, expected->procnum, actual->procnum);
         ok(expected->wParam == actual->wParam,
-            "%s: in procnum %d expecting wParam 0x%x got 0x%x\n",
+            "%s: in procnum %d expecting wParam 0x%lx got 0x%lx\n",
             context, expected->procnum, expected->wParam, actual->wParam);
         expected++;
         actual++;
@@ -169,7 +169,7 @@ static void ok_sequence(const struct message *expected, const char *context)
 static LRESULT WINAPI WndProc1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     struct message msg;
-
+    
     if(message == WM_USER) {
         msg.wParam = wParam;
         msg.procnum = 1;
@@ -183,7 +183,7 @@ static WNDPROC origProc3;
 static LRESULT WINAPI WndProc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     struct message msg;
-
+    
     if(message == WM_USER) {
         msg.wParam = wParam;
         msg.procnum = 3;
@@ -195,12 +195,12 @@ static LRESULT WINAPI WndProc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lP
 static LRESULT WINAPI WndProcSub(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uldSubclass, DWORD_PTR dwRefData)
 {
     struct message msg;
-
+    
     if(message == WM_USER) {
         msg.wParam = wParam;
         msg.procnum = uldSubclass;
         add_message(&msg);
-
+        
         if(lParam) {
             if(dwRefData & DELETE_SELF) {
                 pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass);
@@ -275,20 +275,23 @@ static BOOL RegisterWindowClasses(void)
     cls.lpszMenuName = NULL;
     cls.lpszClassName = "TestSubclass";
     if(!RegisterClassA(&cls)) return FALSE;
-
+    
     return TRUE;
 }
 
 START_TEST(subclass)
 {
     HMODULE hdll;
-
+    
     hdll = GetModuleHandleA("comctl32.dll");
     assert(hdll);
-    pSetWindowSubclass = (void*)GetProcAddress(hdll, "SetWindowSubclass");
-    pRemoveWindowSubclass = (void*)GetProcAddress(hdll, "RemoveWindowSubclass");
-    pDefSubclassProc = (void*)GetProcAddress(hdll, "DefSubclassProc");
-
+    /* Functions have to be loaded by ordinal. Only XP and W2K3 export
+     * them by name.
+     */
+    pSetWindowSubclass = (void*)GetProcAddress(hdll, (LPSTR)410);
+    pRemoveWindowSubclass = (void*)GetProcAddress(hdll, (LPSTR)412);
+    pDefSubclassProc = (void*)GetProcAddress(hdll, (LPSTR)413);
+    
     if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc)
         return;
 
index d5901c0..9489376 100644 (file)
@@ -1,6 +1,7 @@
 /* Unit test suite for tab control.
  *
  * Copyright 2003 Vitaliy Margolen
+ * Copyright 2007 Hagop Hagopian
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <assert.h>
 #include <windows.h>
 #include <commctrl.h>
+#include <stdio.h>
 
 #include "wine/test.h"
+#include "msg.h"
 
 #define DEFAULT_MIN_TAB_WIDTH 54
 #define TAB_DEFAULT_WIDTH 96
 #define TAB_PADDING_X 6
 #define EXTRA_ICON_PADDING 3
+#define MAX_TABLEN 32
+
+#define NUM_MSG_SEQUENCES  2
+#define PARENT_SEQ_INDEX   0
+#define TAB_SEQ_INDEX      1
+
+#define expect(expected, got) ok ( expected == got, "Expected %d, got %d\n", expected, got)
+#define expect_str(expected, got)\
+ ok ( strcmp(expected, got) == 0, "Expected '%s', got '%s'\n", expected, got)
 
 #define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num)
 
 #define CheckSize(hwnd,width,height,msg)\
     SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab);\
     if ((width  >= 0) && (height < 0))\
-       ok (width  == rTab.right  - rTab.left, "%s: Expected width [%d] got [%ld]\n",\
+       ok (width  == rTab.right  - rTab.left, "%s: Expected width [%d] got [%d]\n",\
         msg, (int)width,  rTab.right  - rTab.left);\
     else if ((height >= 0) && (width  < 0))\
-       ok (height == rTab.bottom - rTab.top,  "%s: Expected height [%d] got [%ld]\n",\
+       ok (height == rTab.bottom - rTab.top,  "%s: Expected height [%d] got [%d]\n",\
         msg, (int)height, rTab.bottom - rTab.top);\
     else\
        ok ((width  == rTab.right  - rTab.left) &&\
            (height == rTab.bottom - rTab.top ),\
-           "%s: Expected [%d,%d] got [%ld,%ld]\n", msg, (int)width, (int)height,\
+           "%s: Expected [%d,%d] got [%d,%d]\n", msg, (int)width, (int)height,\
             rTab.right - rTab.left, rTab.bottom - rTab.top);
 
 static HFONT hFont = 0;
 
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message create_parent_wnd_seq[] = {
+    { WM_GETMINMAXINFO, sent },
+    { WM_NCCREATE, sent },
+    { WM_NCCALCSIZE, sent|wparam, 0 },
+    { WM_CREATE, sent },
+    { WM_SHOWWINDOW, sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|defwinproc|optional },
+    { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    /* Win9x adds SWP_NOZORDER below */
+    { WM_WINDOWPOSCHANGED, sent},
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+    { WM_SIZE, sent },
+    { WM_MOVE, sent },
+    { 0 }
+};
+
+static const struct message add_tab_to_parent[] = {
+    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent },
+    { WM_NOTIFYFORMAT, sent|defwinproc },
+    { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 },
+    { WM_PARENTNOTIFY, sent|defwinproc },
+    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent },
+    { 0 }
+};
+
+static const struct message add_tab_to_parent_interactive[] = {
+    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent },
+    { WM_NOTIFYFORMAT, sent|defwinproc },
+    { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 },
+    { WM_PARENTNOTIFY, sent|defwinproc },
+    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent },
+    { WM_SHOWWINDOW, sent},
+    { WM_WINDOWPOSCHANGING, sent},
+    { WM_WINDOWPOSCHANGING, sent},
+    { WM_NCACTIVATE, sent},
+    { WM_ACTIVATE, sent},
+    { WM_IME_SETCONTEXT, sent|defwinproc|optional},
+    { WM_IME_NOTIFY, sent|defwinproc|optional},
+    { WM_SETFOCUS, sent|defwinproc},
+    { WM_WINDOWPOSCHANGED, sent},
+    { WM_SIZE, sent},
+    { WM_MOVE, sent},
+    { 0 }
+};
+
+static const struct message add_tab_control_parent_seq[] = {
+    { WM_NOTIFYFORMAT, sent },
+    { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message add_tab_control_parent_seq_interactive[] = {
+    { WM_NOTIFYFORMAT, sent },
+    { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|optional},
+    { WM_NCACTIVATE, sent},
+    { WM_ACTIVATE, sent},
+    { WM_WINDOWPOSCHANGING, sent|optional},
+    { WM_KILLFOCUS, sent},
+    { WM_IME_SETCONTEXT, sent|optional},
+    { WM_IME_NOTIFY, sent|optional},
+    { 0 }
+};
+
+static const struct message empty_sequence[] = {
+    { 0 }
+};
+
+static const struct message set_min_tab_width_seq[] = {
+    { TCM_SETMINTABWIDTH, sent|wparam, 0 },
+    { TCM_SETMINTABWIDTH, sent|wparam, 0 },
+    { 0 }
+};
+
+static const struct message get_item_count_seq[] = {
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message get_row_count_seq[] = {
+    { TCM_GETROWCOUNT, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message get_item_rect_seq[] = {
+    { TCM_GETITEMRECT, sent },
+    { TCM_GETITEMRECT, sent },
+    { 0 }
+};
+
+static const struct message getset_cur_focus_seq[] = {
+    { TCM_SETCURFOCUS, sent|lparam, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_SETCURFOCUS, sent|lparam, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_SETCURSEL, sent|lparam, 0 },
+    { TCM_SETCURFOCUS, sent|lparam, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message getset_cur_sel_seq[] = {
+    { TCM_SETCURSEL, sent|lparam, 0 },
+    { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_SETCURSEL, sent|lparam, 0 },
+    { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
+    { TCM_SETCURSEL, sent|lparam, 0 },
+    { TCM_SETCURSEL, sent|lparam, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message getset_extended_style_seq[] = {
+    { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
+    { TCM_SETEXTENDEDSTYLE, sent },
+    { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
+    { TCM_SETEXTENDEDSTYLE, sent },
+    { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message getset_unicode_format_seq[] = {
+    { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
+    { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
+    { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
+    { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
+    { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
+    { 0 }
+};
+
+static const struct message getset_item_seq[] = {
+    { TCM_SETITEMA, sent },
+    { TCM_GETITEMA, sent },
+    { TCM_GETITEMA, sent },
+    { 0 }
+};
+
+static const struct message getset_tooltip_seq[] = {
+    { WM_NOTIFYFORMAT, sent },
+    { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_NOTIFYFORMAT, sent },
+    { TCM_SETTOOLTIPS, sent|lparam, 0 },
+    { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
+    { TCM_SETTOOLTIPS, sent|lparam, 0 },
+    { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message getset_tooltip_parent_seq[] = {
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { 0 }
+};
+
+static const struct message insert_focus_seq[] = {
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_INSERTITEM, sent|wparam, 1 },
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_INSERTITEM, sent|wparam, 2 },
+    { WM_NOTIFYFORMAT, sent|defwinproc, },
+    { WM_QUERYUISTATE, sent|defwinproc, },
+    { WM_PARENTNOTIFY, sent|defwinproc, },
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_INSERTITEM, sent|wparam, 3 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+static const struct message delete_focus_seq[] = {
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_DELETEITEM, sent|wparam|lparam, 1, 0 },
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { TCM_DELETEITEM, sent|wparam|lparam, 0, 0 },
+    { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
+    { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
+    { 0 }
+};
+
+
 static HWND
 create_tabcontrol (DWORD style, DWORD mask)
 {
@@ -94,6 +309,195 @@ create_tabcontrol (DWORD style, DWORD mask)
     return handle;
 }
 
+static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL registerParentWindowClass(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parentWindowProcess;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Tab test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND createParentWindow(void)
+{
+    if (!registerParentWindowClass())
+        return NULL;
+
+    return CreateWindowEx(0, "Tab test parent class",
+                          "Tab test parent window",
+                          WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                          WS_MAXIMIZEBOX | WS_VISIBLE,
+                          0, 0, 100, 100,
+                          GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
+}
+
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("tab: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, TAB_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT nTabs)
+{
+    HWND tabHandle;
+    TCITEM tcNewTab;
+    struct subclass_info *info;
+    RECT rect;
+    INT i;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    GetClientRect(parent_wnd, &rect);
+
+    tabHandle = CreateWindow (
+        WC_TABCONTROLA,
+        "TestTab",
+        WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
+        0, 0, rect.right, rect.bottom,
+        parent_wnd, NULL, NULL, 0);
+
+    assert(tabHandle);
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess);
+    SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)info);
+
+    tcNewTab.mask = mask;
+
+    for (i = 0; i < nTabs; i++)
+    {
+        char tabName[MAX_TABLEN];
+
+        sprintf(tabName, "Tab %d", i+1);
+        tcNewTab.pszText = tabName;
+        tcNewTab.iImage = i;
+        SendMessage (tabHandle, TCM_INSERTITEM, i, (LPARAM) &tcNewTab);
+    }
+
+    if (winetest_interactive)
+    {
+        ShowWindow (tabHandle, SW_SHOW);
+        RedrawWindow (tabHandle, NULL, 0, RDW_UPDATENOW);
+        Sleep (1000);
+    }
+
+    return tabHandle;
+}
+
+static HWND create_tooltip (HWND hTab, char toolTipText[])
+{
+    HWND hwndTT;
+
+    TOOLINFO ti;
+    LPTSTR lptstr = toolTipText;
+    RECT rect;
+
+    /* Creating a tooltip window*/
+    hwndTT = CreateWindowEx(
+        WS_EX_TOPMOST,
+        TOOLTIPS_CLASS,
+        NULL,
+        WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+        hTab, NULL, 0, NULL);
+
+    SetWindowPos(
+        hwndTT,
+        HWND_TOPMOST,
+        0, 0, 0, 0,
+        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
+    GetClientRect (hTab, &rect);
+
+    /* Initialize members of toolinfo*/
+    ti.cbSize = sizeof(TOOLINFO);
+    ti.uFlags = TTF_SUBCLASS;
+    ti.hwnd = hTab;
+    ti.hinst = 0;
+    ti.uId = 0;
+    ti.lpszText = lptstr;
+
+    ti.rect = rect;
+
+    /* Add toolinfo structure to the tooltip control */
+    SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
+
+    return hwndTT;
+}
+
 static void test_tab(INT nMinTabWidth)
 {
     HWND hwTab;
@@ -110,7 +514,7 @@ static void test_tab(INT nMinTabWidth)
     hdc = GetDC(hwTab);
     hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0));
     GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
-    trace("Tab1 text size: size.cx=%ld size.cy=%ld\n", size.cx, size.cy);
+    trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy);
     SelectObject(hdc, hOldFont);
     ReleaseDC(hwTab, hdc);
 
@@ -223,8 +627,338 @@ static void test_tab(INT nMinTabWidth)
     DeleteObject(hFont);
 }
 
+static void test_getters_setters(HWND parent_wnd, INT nTabs)
+{
+    HWND hTab;
+    RECT rTab;
+    INT nTabsRetrieved;
+    INT rowCount;
+
+    ok(parent_wnd != NULL, "no parent window!\n");
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
+    ok(hTab != NULL, "Failed to create tab control\n");
+
+    if(!winetest_interactive)
+        ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent,
+                    "Tab sequence, after adding tab control to parent", TRUE);
+    else
+        ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent_interactive,
+                    "Tab sequence, after adding tab control to parent", TRUE);
+
+    if(!winetest_interactive)
+        ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq,
+                    "Parent after sequence, adding tab control to parent", TRUE);
+    else
+        ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq_interactive,
+                    "Parent after sequence, adding tab control to parent", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    todo_wine{
+        expect(DEFAULT_MIN_TAB_WIDTH, (int)SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1));
+    }
+    ok_sequence(sequences, TAB_SEQ_INDEX, set_min_tab_width_seq, "Set minTabWidth test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set minTabWidth test parent sequence", FALSE);
+
+    /* Testing GetItemCount */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(nTabs, nTabsRetrieved);
+    ok_sequence(sequences, TAB_SEQ_INDEX, get_item_count_seq, "Get itemCount test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset itemCount test parent sequence", FALSE);
+
+    /* Testing GetRowCount */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    rowCount = SendMessage(hTab, TCM_GETROWCOUNT, 0, 0);
+    expect(1, rowCount);
+    ok_sequence(sequences, TAB_SEQ_INDEX, get_row_count_seq, "Get rowCount test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get rowCount test parent sequence", FALSE);
+
+    /* Testing GetItemRect */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n");
+    CheckSize(hTab, TAB_DEFAULT_WIDTH, -1 , "Default Width");
+    ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE);
+
+    /* Testing CurFocus */
+    {
+        INT focusIndex;
+
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        /* Testing CurFocus with largest appropriate value */
+        SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0);
+        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+            expect(nTabs-1, focusIndex);
+
+        /* Testing CurFocus with negative value */
+        SendMessage(hTab, TCM_SETCURFOCUS, -10, 0);
+        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+            expect(-1, focusIndex);
+
+        /* Testing CurFocus with value larger than number of tabs */
+        focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
+        todo_wine{
+            expect(-1, focusIndex);
+        }
+
+        SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0);
+        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+            expect(1, focusIndex);
+
+        ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE);
+    }
+
+    /* Testing CurSel */
+    {
+        INT selectionIndex;
+        INT focusIndex;
+
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        /* Testing CurSel with largest appropriate value */
+        selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0);
+            expect(1, selectionIndex);
+        selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
+            expect(nTabs-1, selectionIndex);
+
+        /* Focus should switch with selection */
+        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+            expect(nTabs-1, focusIndex);
+
+        /* Testing CurSel with negative value */
+        SendMessage(hTab, TCM_SETCURSEL, -10, 0);
+        selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
+            expect(-1, selectionIndex);
+
+        /* Testing CurSel with value larger than number of tabs */
+        selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
+            expect(-1, selectionIndex);
+
+        selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0);
+            expect(-1, selectionIndex);
+        selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+            expect(1, selectionIndex);
+
+        ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE);
+        ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE);
+    }
+
+    /* Testing ExtendedStyle */
+    {
+        DWORD prevExtendedStyle;
+        DWORD extendedStyle;
+
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        /* Testing Flat Separators */
+        extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
+        prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
+            expect(extendedStyle, prevExtendedStyle);
+
+        extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
+        todo_wine{
+            expect(TCS_EX_FLATSEPARATORS, extendedStyle);
+        }
+
+        /* Testing Register Drop */
+        prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
+            expect(extendedStyle, prevExtendedStyle);
+
+        extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
+        todo_wine{
+            expect(TCS_EX_REGISTERDROP, extendedStyle);
+        }
+
+        ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE);
+        ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE);
+    }
+
+    /* Testing UnicodeFormat */
+    {
+        INT unicodeFormat;
+
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
+        todo_wine{
+            expect(0, unicodeFormat);
+        }
+        unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
+            expect(1, unicodeFormat);
+
+        unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
+            expect(1, unicodeFormat);
+        unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
+            expect(0, unicodeFormat);
+
+        unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
+            expect(0, unicodeFormat);
+
+        ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE);
+        ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE);
+    }
+
+    /* Testing GetSet Item */
+    {
+        TCITEM tcItem;
+        char szText[32] = "New Label";
+
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        tcItem.mask = TCIF_TEXT;
+        tcItem.pszText = &szText[0];
+        tcItem.cchTextMax = sizeof(szText);
+
+        ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
+        ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
+        expect_str("New Label", tcItem.pszText);
+
+        ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n");
+        expect_str("Tab 2", tcItem.pszText);
+
+        ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE);
+        ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE);
+    }
+
+    /* Testing GetSet ToolTip */
+    {
+        HWND toolTip;
+        char toolTipText[32] = "ToolTip Text Test";
+
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        toolTip = create_tooltip(hTab, toolTipText);
+        SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0);
+        ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
+
+        SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) NULL, 0);
+        ok (NULL  == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
+
+        ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE);
+        ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE);
+    }
+
+    DestroyWindow(hTab);
+}
+
+static void test_insert_focus(HWND parent_wnd)
+{
+    HWND hTab;
+    INT nTabsRetrieved;
+    INT r;
+    TCITEM tcNewTab;
+    DWORD mask = TCIF_TEXT|TCIF_IMAGE;
+    static char tabName[] = "TAB";
+    tcNewTab.mask = mask;
+    tcNewTab.pszText = tabName;
+
+    ok(parent_wnd != NULL, "no parent window!\n");
+
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, mask, 0);
+    ok(hTab != NULL, "Failed to create tab control\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(0, nTabsRetrieved);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(-1, r);
+
+    tcNewTab.iImage = 1;
+    r = SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
+    expect(0, r);
+
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(1, nTabsRetrieved);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(0, r);
+
+    tcNewTab.iImage = 2;
+    r = SendMessage(hTab, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
+    expect(1, r);
+
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(2, nTabsRetrieved);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(0, r);
+
+    r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
+    expect(0, r);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(-1, r);
+
+    tcNewTab.iImage = 3;
+    r = SendMessage(hTab, TCM_INSERTITEM, 3, (LPARAM) &tcNewTab);
+    expect(2, r);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(2, r);
+
+    ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", FALSE);
+
+    DestroyWindow(hTab);
+}
+
+static void test_delete_focus(HWND parent_wnd)
+{
+    HWND hTab;
+    INT nTabsRetrieved;
+    INT r;
+
+    ok(parent_wnd != NULL, "no parent window!\n");
+
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 2);
+    ok(hTab != NULL, "Failed to create tab control\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(2, nTabsRetrieved);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(0, r);
+
+    r = SendMessage(hTab, TCM_DELETEITEM, 1, 0);
+    expect(1, r);
+
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(1, nTabsRetrieved);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(0, r);
+
+    r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
+    expect(0, r);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(-1, r);
+
+    r = SendMessage(hTab, TCM_DELETEITEM, 0, 0);
+    expect(1, r);
+
+    nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
+    expect(0, nTabsRetrieved);
+
+    r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(-1, r);
+
+    ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", FALSE);
+
+    DestroyWindow(hTab);
+}
+
 START_TEST(tab)
 {
+    HWND parent_wnd;
     LOGFONTA logfont;
 
     lstrcpyA(logfont.lfFaceName, "Arial");
@@ -246,4 +980,17 @@ START_TEST(tab)
     test_tab(54);
     trace ("Testing with MinWidth set to 94\n");
     test_tab(94);
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    parent_wnd = createParentWindow();
+    ok(parent_wnd != NULL, "Failed to create parent window!\n");
+
+    /* Testing getters and setters with 5 tabs */
+    test_getters_setters(parent_wnd, 5);
+
+    test_insert_focus(parent_wnd);
+    test_delete_focus(parent_wnd);
+
+    DestroyWindow(parent_wnd);
 }
index 179eefd..be88bef 100644 (file)
@@ -1,3 +1,5 @@
+/* Automatically generated file; DO NOT EDIT!! */
+
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
@@ -5,36 +7,48 @@
 #include "wine/test.h"
 
 extern void func_comboex(void);
+extern void func_datetime(void);
 extern void func_dpa(void);
 extern void func_header(void);
 extern void func_imagelist(void);
 extern void func_listview(void);
+extern void func_misc(void);
 extern void func_monthcal(void);
 extern void func_mru(void);
+extern void func_msg(void);
 extern void func_progress(void);
 extern void func_propsheet(void);
+extern void func_rebar(void);
+extern void func_status(void);
 extern void func_subclass(void);
 extern void func_tab(void);
 extern void func_toolbar(void);
 extern void func_tooltips(void);
+extern void func_trackbar(void);
 extern void func_treeview(void);
 extern void func_updown(void);
 
 const struct test winetest_testlist[] =
 {
     { "comboex", func_comboex },
+    { "datetime", func_datetime },
     { "dpa", func_dpa },
     { "header", func_header },
     { "imagelist", func_imagelist },
     { "listview", func_listview },
+    { "misc", func_misc },
     { "monthcal", func_monthcal },
     { "mru", func_mru },
+    { "msg", func_msg },
     { "progress", func_progress },
     { "propsheet", func_propsheet },
+    { "rebar", func_rebar },
+    { "status", func_status },
     { "subclass", func_subclass },
     { "tab", func_tab },
     { "toolbar", func_toolbar },
     { "tooltips", func_tooltips },
+    { "trackbar", func_trackbar },
     { "treeview", func_treeview },
     { "updown", func_updown },
     { 0, 0 }
index 1ccc80c..b094a4b 100644 (file)
@@ -1,6 +1,7 @@
 /* Unit tests for treeview.
  *
  * Copyright 2005 Krzysztof Foltman
+ * Copyright 2007 Mikolaj Zalewski
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "winuser.h"
 #include "winnls.h"
 #include "winreg.h"
-#include "commctrl.h"
+#include "commctrl.h" 
+
+#include "resources.h"
 
 #include "wine/test.h"
 
+static HWND hMainWnd;
+static BOOL g_fBlockHotItemChange;
+static BOOL g_fReceivedHotItemChange;
+static BOOL g_fExpectedHotItemOld;
+static BOOL g_fExpectedHotItemNew;
+static DWORD g_dwExpectedDispInfoMask;
+
+#define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
+    val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \
+    val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom);
+#define compare(val, exp, format) ok((val) == (exp), #val " value " format " expected " format "\n", (val), (exp));
+
 static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
   p->iBitmap = -2;
   p->idCommand = idCommand;
@@ -38,71 +54,1038 @@ static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
   p->iString = nString;
 }
 
+static LRESULT MyWnd_Notify(LPARAM lParam)
+{
+    NMHDR *hdr = (NMHDR *)lParam;
+    NMTBHOTITEM *nmhi;
+    NMTBDISPINFO *nmdisp;
+    switch (hdr->code)
+    {
+        case TBN_HOTITEMCHANGE:
+            nmhi = (NMTBHOTITEM *)lParam;
+            g_fReceivedHotItemChange = TRUE;
+            if (g_fExpectedHotItemOld != g_fExpectedHotItemNew)
+            {
+                compare(nmhi->idOld, g_fExpectedHotItemOld, "%d");
+                compare(nmhi->idNew, g_fExpectedHotItemNew, "%d");
+            }
+            if (g_fBlockHotItemChange)
+                return 1;
+            break;
+
+        case TBN_GETDISPINFOA:
+            ok(FALSE, "TBN_GETDISPINFOA received\n");
+            break;
+
+        case TBN_GETDISPINFOW:
+            nmdisp = (NMTBDISPINFOA *)lParam;
+
+            compare(nmdisp->dwMask, g_dwExpectedDispInfoMask, "%x");
+            compare(nmdisp->iImage, -1, "%d");
+            ok(nmdisp->pszText == NULL, "pszText is not NULL\n");
+        break;
+    }
+    return 0;
+}
+
 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    switch(msg) {
+    switch (msg)
+    {
+        case WM_NOTIFY:
+            return MyWnd_Notify(lParam);
+    }
+    return DefWindowProcA(hWnd, msg, wParam, lParam);
+}
+
+static void basic_test(void)
+{
+    TBBUTTON buttons[9];
+    HWND hToolbar;
+    int i;
+    for (i=0; i<9; i++)
+        MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
+    MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
+    MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
+
+    hToolbar = CreateToolbarEx(hMainWnd,
+        WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
+        WS_CHILD | TBSTYLE_LIST,
+        100,
+        0, NULL, (UINT)0,
+        buttons, sizeof(buttons)/sizeof(buttons[0]),
+        0, 0, 20, 16, sizeof(TBBUTTON));
+    ok(hToolbar != NULL, "Toolbar creation\n");
+    SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
+
+    /* test for exclusion working inside a separator-separated :-) group */
+    SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
+
+    SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
+
+    SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
+
+    /* test for inter-group crosstalk, ie. two radio groups interfering with each other */
+    SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
+
+    SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
+
+    SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
+    ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
+    ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
+
+    /* tests with invalid index */
+    compare(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 0xdeadbeef, 0), -1L, "%ld");
+    compare(SendMessage(hToolbar, TB_ISBUTTONPRESSED, 0xdeadbeef, 0), -1L, "%ld");
+    compare(SendMessage(hToolbar, TB_ISBUTTONENABLED, 0xdeadbeef, 0), -1L, "%ld");
+    compare(SendMessage(hToolbar, TB_ISBUTTONINDETERMINATE, 0xdeadbeef, 0), -1L, "%ld");
+    compare(SendMessage(hToolbar, TB_ISBUTTONHIGHLIGHTED, 0xdeadbeef, 0), -1L, "%ld");
+    compare(SendMessage(hToolbar, TB_ISBUTTONHIDDEN, 0xdeadbeef, 0), -1L, "%ld");
+
+    DestroyWindow(hToolbar);
+}
+
+static void rebuild_toolbar(HWND *hToolbar)
+{
+    if (*hToolbar != NULL)
+        DestroyWindow(*hToolbar);
+    *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
+        hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
+    ok(*hToolbar != NULL, "Toolbar creation problem\n");
+    ok(SendMessage(*hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n");
+    ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
+    ok(SendMessage(*hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n");
+}
+
+static void rebuild_toolbar_with_buttons(HWND *hToolbar)
+{
+    TBBUTTON buttons[5];
+    rebuild_toolbar(hToolbar);
+    
+    ZeroMemory(&buttons, sizeof(buttons));
+    buttons[0].idCommand = 1;
+    buttons[0].fsStyle = BTNS_BUTTON;
+    buttons[0].fsState = TBSTATE_ENABLED;
+    buttons[0].iString = -1;
+    buttons[1].idCommand = 3;
+    buttons[1].fsStyle = BTNS_BUTTON;
+    buttons[1].fsState = TBSTATE_ENABLED;
+    buttons[1].iString = -1;
+    buttons[2].idCommand = 5;
+    buttons[2].fsStyle = BTNS_SEP;
+    buttons[2].fsState = TBSTATE_ENABLED;
+    buttons[2].iString = -1;
+    buttons[3].idCommand = 7;
+    buttons[3].fsStyle = BTNS_BUTTON;
+    buttons[3].fsState = TBSTATE_ENABLED;
+    buttons[3].iString = -1;
+    buttons[4].idCommand = 9;
+    buttons[4].fsStyle = BTNS_BUTTON;
+    buttons[4].fsState = 0;  /* disabled */
+    buttons[4].iString = -1;
+    ok(SendMessage(*hToolbar, TB_ADDBUTTONS, 5, (LPARAM)buttons) == 1, "TB_ADDBUTTONS failed\n");
+    ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
+}
+
+
+#define CHECK_IMAGELIST(count, dx, dy) { \
+    int cx, cy; \
+    HIMAGELIST himl = (HIMAGELIST)SendMessageA(hToolbar, TB_GETIMAGELIST, 0, 0); \
+    ok(himl != NULL, "No image list\n"); \
+    if (himl != NULL) {\
+        ok(ImageList_GetImageCount(himl) == count, "Images count mismatch - %d vs %d\n", count, ImageList_GetImageCount(himl)); \
+        ImageList_GetIconSize(himl, &cx, &cy); \
+        ok(cx == dx && cy == dy, "Icon size mismatch - %dx%d vs %dx%d\n", dx, dy, cx, cy); \
+    } \
+}
+
+static void test_add_bitmap(void)
+{
+    HWND hToolbar = NULL;
+    TBADDBITMAP bmp128;
+    TBADDBITMAP bmp80;
+    TBADDBITMAP stdsmall;
+    TBADDBITMAP addbmp;
+    HIMAGELIST himl;
+    INT ret;
+
+    /* empty 128x15 bitmap */
+    bmp128.hInst = GetModuleHandle(NULL);
+    bmp128.nID = IDB_BITMAP_128x15;
+
+    /* empty 80x15 bitmap */
+    bmp80.hInst = GetModuleHandle(NULL);
+    bmp80.nID = IDB_BITMAP_80x15;
+
+    /* standard bitmap - 240x15 pixels */
+    stdsmall.hInst = HINST_COMMCTRL;
+    stdsmall.nID = IDB_STD_SMALL_COLOR;
+
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(8, 16, 16);
+    
+    /* adding more bitmaps */
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 8, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(13, 16, 16);
+    /* adding the same bitmap will simply return the index of the already loaded block */
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 8, (LPARAM)&bmp128);
+    ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(13, 16, 16);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
+    ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(13, 16, 16);
+    /* even if we increase the wParam */
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 55, (LPARAM)&bmp80);
+    ok(ret == 8, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(13, 16, 16);
+
+    /* when the wParam is smaller than the bitmaps count but non-zero, all the bitmaps will be added*/
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(8, 16, 16);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80);
+    ok(ret == 3, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    /* the returned value is misleading - id 8 is the id of the first icon from bmp80 */
+    CHECK_IMAGELIST(13, 16, 16);
+
+    /* the same for negative wParam */
+    rebuild_toolbar(&hToolbar);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, -143, (LPARAM)&bmp128);
+    ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(8, 16, 16);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
+    ok(ret == -143, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(13, 16, 16);
+
+    /* for zero only one bitmap will be added */
+    rebuild_toolbar(&hToolbar);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&bmp80);
+    ok(ret == 0, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(1, 16, 16);
+
+    /* if wParam is larger than the amount of icons, the list is grown */
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(100, 16, 16);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128);
+    ok(ret == 100, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(200, 16, 16);
+
+    /* adding built-in items - the wParam is ignored */
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp80) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(5, 16, 16);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 5, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(20, 16, 16);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 20, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(28, 16, 16);
+
+    /* when we increase the bitmap size, less icons will be created */
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(6, 20, 20);
+    ret = SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp80);
+    ok(ret == 1, "TB_ADDBITMAP - unexpected return %d\n", ret);
+    CHECK_IMAGELIST(10, 20, 20);
+    /* the icons can be resized - an UpdateWindow is needed as this probably happens during WM_PAINT */
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(26, 8, 8);
+    /* loading a standard bitmaps automatically resizes the icons */
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&stdsmall) == 2, "TB_ADDBITMAP - unexpected return\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(28, 16, 16);
+
+    /* two more SETBITMAPSIZE tests */
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(100, 16, 16);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 100, (LPARAM)&bmp80) == 100, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(200, 16, 16);
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(200, 8, 8);
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(200, 30, 30);
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 5, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(8, 16, 16);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 3, (LPARAM)&bmp80) == 5, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(13, 16, 16);
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(30, 30)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(8, 30, 30);
+    /* when the width or height is zero, set it to 1 */
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(208, 1, 1);
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0, 5)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(208, 1, 5);
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(5, 0)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    CHECK_IMAGELIST(41, 5, 1);
+
+    /* the control can add bitmaps to an existing image list */
+    rebuild_toolbar(&hToolbar);
+    himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
+    ok(himl != NULL, "failed to create imagelist\n");
+    ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
+    CHECK_IMAGELIST(4, 20, 15);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(10, 20, 15);
+    /* however TB_SETBITMAPSIZE/add std bitmap won't change the image size (the button size does change) */
+    ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(8, 8)) == TRUE, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(15, 14), "%x");
+    CHECK_IMAGELIST(10, 20, 15);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&stdsmall) == 1, "TB_SETBITMAPSIZE failed\n");
+    UpdateWindow(hToolbar);
+    compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
+    CHECK_IMAGELIST(22, 20, 15);
+
+    /* check standard bitmaps */
+    addbmp.hInst = HINST_COMMCTRL;
+    addbmp.nID = IDB_STD_SMALL_COLOR;
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(15, 16, 16);
+    compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(23, 22), "%x");
+    addbmp.nID = IDB_STD_LARGE_COLOR;
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(15, 24, 24);
+    compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(31, 30), "%x");
+
+    addbmp.nID = IDB_VIEW_SMALL_COLOR;
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(12, 16, 16);
+    addbmp.nID = IDB_VIEW_LARGE_COLOR;
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(12, 24, 24);
+
+    addbmp.nID = IDB_HIST_SMALL_COLOR;
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(5, 16, 16);
+    addbmp.nID = IDB_HIST_LARGE_COLOR;
+    rebuild_toolbar(&hToolbar);
+    ok(SendMessageA(hToolbar, TB_ADDBITMAP, 1, (LPARAM)&addbmp) == 0, "TB_ADDBITMAP - unexpected return\n");
+    CHECK_IMAGELIST(5, 24, 24);
+
+
+    DestroyWindow(hToolbar);
+}
+
+#define CHECK_STRING_TABLE(count, tab) { \
+        INT _i; \
+        CHAR _buf[260]; \
+        for (_i = 0; _i < (count); _i++) {\
+            ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, _i), (LPARAM)_buf); \
+            ok(ret >= 0, "TB_GETSTRING - unexpected return %d while checking string %d\n", ret, _i); \
+            if (ret >= 0) \
+                ok(strcmp(_buf, (tab)[_i]) == 0, "Invalid string #%d - '%s' vs '%s'\n", _i, (tab)[_i], _buf); \
+        } \
+        ok(SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, (count)), (LPARAM)_buf) == -1, \
+            "Too many string in table\n"); \
+    }
+
+static void test_add_string(void)
+{
+    LPCSTR test1 = "a\0b\0";
+    LPCSTR test2 = "|a|b||\0";
+    LPCSTR ret1[] = {"a", "b"};
+    LPCSTR ret2[] = {"a", "b", "|a|b||"};
+    LPCSTR ret3[] = {"a", "b", "|a|b||", "p", "q"};
+    LPCSTR ret4[] = {"a", "b", "|a|b||", "p", "q", "p"};
+    LPCSTR ret5[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q"};
+    LPCSTR ret6[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q"};
+    LPCSTR ret7[] = {"a", "b", "|a|b||", "p", "q", "p", "p", "q", "p", "", "q", "br", "c", "d"};
+    HWND hToolbar = NULL;
+    TBBUTTON button;
+    int ret;
+
+    rebuild_toolbar(&hToolbar);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
+    ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(2, ret1);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
+    ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(3, ret2);
+
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD1);
+    ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(3, ret2);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD2);
+    ok(ret == 3, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(5, ret3);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD3);
+    ok(ret == 5, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(6, ret4);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD4);
+    ok(ret == 6, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(8, ret5);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD5);
+    ok(ret == 8, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(11, ret6);
+    ret = SendMessageA(hToolbar, TB_ADDSTRINGA, (WPARAM)GetModuleHandle(NULL), IDS_TBADD7);
+    ok(ret == 11, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    CHECK_STRING_TABLE(14, ret7);
+
+    ZeroMemory(&button, sizeof(button));
+    button.iString = (UINT_PTR)"Test";
+    SendMessageA(hToolbar, TB_INSERTBUTTONA, 0, (LPARAM)&button);
+    CHECK_STRING_TABLE(14, ret7);
+    SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&button);
+    CHECK_STRING_TABLE(14, ret7);
+
+    DestroyWindow(hToolbar);
+}
+
+static void expect_hot_notify(int idold, int idnew)
+{
+    g_fExpectedHotItemOld = idold;
+    g_fExpectedHotItemNew = idnew;
+    g_fReceivedHotItemChange = FALSE;
+}
+
+#define check_hot_notify() \
+    ok(g_fReceivedHotItemChange, "TBN_HOTITEMCHANGE not received\n"); \
+    g_fExpectedHotItemOld = g_fExpectedHotItemNew = 0;
+
+static void test_hotitem(void)
+{
+    HWND hToolbar = NULL;
+    TBBUTTONINFO tbinfo;
+    LRESULT ret;
+
+    g_fBlockHotItemChange = FALSE;
+
+    rebuild_toolbar_with_buttons(&hToolbar);
+    /* set TBSTYLE_FLAT. comctl5 allows hot items only for such toolbars.
+     * comctl6 doesn't have this requirement even when theme == NULL */
+    SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_FLAT | GetWindowLong(hToolbar, GWL_STYLE));
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == -1, "Hot item: %ld, expected -1\n", ret);
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
+    ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == 1, "Hot item: %ld, expected 1\n", ret);
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
+    ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
+
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeef, 0);
+    ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == 2, "Hot item: %lx, expected 2\n", ret);
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeef, 0);
+    ok(ret == 2, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
+
+    expect_hot_notify(0, 7);
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
+    ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
+    check_hot_notify();
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
+    g_fBlockHotItemChange = TRUE;
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 2, 0);
+    ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 2\n", ret);
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == 3, "Hot item: %lx, expected 3\n", ret);
+    g_fBlockHotItemChange = FALSE;
+
+    g_fReceivedHotItemChange = FALSE;
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 0xbeaf, 0);
+    ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
+    ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received for invalid parameter\n");
+
+    g_fReceivedHotItemChange = FALSE;
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
+    ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
+    ok(g_fReceivedHotItemChange == FALSE, "TBN_HOTITEMCHANGE received after a duplication\n");
+
+    expect_hot_notify(7, 0);
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, -0xbeaf, 0);
+    ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
+    check_hot_notify();
+    SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
+
+    /* setting disabled buttons will generate a notify with the button id but no button will be hot */
+    expect_hot_notify(7, 9);
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 4, 0);
+    ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
+    check_hot_notify();
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == -1, "Hot item: %lx, expected -1\n", ret);
+    /* enabling the button won't change that */
+    SendMessage(hToolbar, TB_ENABLEBUTTON, 9, TRUE);
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
+
+    /* disabling a hot button works */
+    ret = SendMessage(hToolbar, TB_SETHOTITEM, 3, 0);
+    ok(ret == -1, "TB_SETHOTITEM returned %ld, expected -1\n", ret);
+    g_fReceivedHotItemChange = FALSE;
+    SendMessage(hToolbar, TB_ENABLEBUTTON, 7, FALSE);
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == 3, "TB_SETHOTITEM returned %ld, expected 3\n", ret);
+    ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
+
+    SendMessage(hToolbar, TB_SETHOTITEM, 1, 0);
+    tbinfo.cbSize = sizeof(TBBUTTONINFO);
+    tbinfo.dwMask = TBIF_STATE;
+    tbinfo.fsState = 0;  /* disabled */
+    g_fReceivedHotItemChange = FALSE;
+    ok(SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) == TRUE, "TB_SETBUTTONINFO failed\n");
+    ret = SendMessage(hToolbar, TB_GETHOTITEM, 0, 0);
+    ok(ret == 1, "TB_SETHOTITEM returned %ld, expected 1\n", ret);
+    ok(g_fReceivedHotItemChange == FALSE, "Unexpected TBN_HOTITEMCHANGE\n");
+
+    DestroyWindow(hToolbar);
+}
+
+#if 0  /* use this to generate more tests*/
+
+static void dump_sizes(HWND hToolbar)
+{
+    SIZE sz;
+    RECT r;
+    int count = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0);
+    int i;
 
-    case WM_CREATE:
+    GetClientRect(hToolbar, &r);
+    SendMessageA(hToolbar, TB_GETMAXSIZE, 0, &sz);
+    printf("  { {%d, %d, %d, %d}, {%d, %d}, %d, {", r.left, r.top, r.right, r.bottom,
+        sz.cx, sz.cy, count);
+    for (i=0; i<count; i++)
     {
-        TBBUTTON buttons[9];
-        int i;
-        HWND hToolbar;
-        for (i=0; i<9; i++)
-            MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
-        MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
-        MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
-
-        hToolbar = CreateToolbarEx(hWnd,
-            WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
-            WS_CHILD | TBSTYLE_LIST,
-            100,
-            0, NULL, (UINT)0,
-            buttons, sizeof(buttons)/sizeof(buttons[0]),
-            0, 0, 20, 16, sizeof(TBBUTTON));
-        ok(hToolbar != NULL, "Toolbar creation\n");
-
-        SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
-
-        /* test for exclusion working inside a separator-separated :-) group */
-        SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
-
-        SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
-
-        SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
-
-        /* test for inter-group crosstalk, ie. two radio groups interfering with each other */
-        SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
-
-        SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
-
-        SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
-        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
-        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
-        PostMessage(hWnd, WM_CLOSE, 0, 0);
-        return 0;
+        SendMessageA(hToolbar, TB_GETITEMRECT, i, &r);
+        printf("%s{%3d, %3d, %3d, %3d}, ", (i%3==0 ? "\n    " : ""), r.left, r.top, r.right, r.bottom);
     }
-    case WM_DESTROY:
-        PostQuitMessage(0);
-        break;
+    printf("\n  }, }, \n");
+}
+
+#define check_sizes() dump_sizes(hToolbar);
+#define check_sizes_todo(todomask) dump_sizes(hToolbar);
+
+#else
+
+typedef struct
+{
+    RECT rcClient;
+    SIZE szMin;
+    INT nButtons;
+    RECT rcButtons[100];
+} tbsize_result_t;
 
-    default:
-        return DefWindowProcA(hWnd, msg, wParam, lParam);
+static tbsize_result_t tbsize_results[] =
+{
+  { {0, 0, 672, 26}, {100, 22}, 5, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
+    { 54,   2,  77,  24}, { 77,   2, 100,  24},
+  }, },
+  { {0, 0, 672, 26}, {146, 22}, 7, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
+    { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
+    {  0,  24,  23,  46},
+  }, },
+  { {0, 0, 672, 48}, {146, 22}, 7, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
+    { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
+    {  0,  24,  23,  46},
+  }, },
+  { {0, 0, 672, 26}, {146, 22}, 7, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
+    { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
+    {123,   2, 146,  24},
+  }, },
+  { {0, 0, 672, 26}, {192, 22}, 9, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
+    { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
+    {123,   2, 146,  24}, {146,   2, 169,  24}, {169,   2, 192,  24},
+  }, },
+  { {0, 0, 672, 92}, {882, 22}, 39, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,   2,   8,  29},
+    {  0,  29,  23,  51}, { 23,  29,  46,  51}, { 46,  29,  69,  51},
+    { 69,  29,  92,  51}, { 92,  29, 115,  51}, {115,  29, 138,  51},
+    {138,  29, 161,  51}, {161,  29, 184,  51}, {184,  29, 207,  51},
+    {207,  29, 230,  51}, {230,  29, 253,  51}, {253,  29, 276,  51},
+    {276,  29, 299,  51}, {299,  29, 322,  51}, {322,  29, 345,  51},
+    {345,  29, 368,  51}, {368,  29, 391,  51}, {391,  29, 414,  51},
+    {414,  29, 437,  51}, {437,  29, 460,  51}, {460,  29, 483,  51},
+    {483,  29, 506,  51}, {506,  29, 529,  51}, {529,  29, 552,  51},
+    {552,  29, 575,  51}, {575,  29, 598,  51}, {598,  29, 621,  51},
+    {621,  29, 644,  51}, {644,  29, 667,  51}, {  0,  51,  23,  73},
+    { 23,  51,  46,  73}, { 46,  51,  69,  73}, { 69,  51,  92,  73},
+    { 92,  51, 115,  73}, {115,  51, 138,  73}, {138,  51, 161,  73},
+  }, },
+  { {0, 0, 48, 226}, {23, 140}, 7, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  94,  24},
+    { 94,   2, 117,  24}, {117,   2, 140,  24}, {140,   2, 163,  24},
+    {  0,  24,  23,  46},
+  }, },
+  { {0, 0, 92, 226}, {23, 140}, 7, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, {  0,  24,  92,  32},
+    {  0,  32,  23,  54}, { 23,  32,  46,  54}, { 46,  32,  69,  54},
+    { 69,  32,  92,  54},
+  }, },
+  { {0, 0, 672, 26}, {194, 30}, 7, {
+    {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
+    { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
+    {  0,  32,  31,  62},
+  }, },
+  { {0, 0, 672, 64}, {194, 30}, 7, {
+    {  0,   2,  31,  32}, { 31,   2,  62,  32}, { 62,   2,  70,  32},
+    { 70,   2, 101,  32}, {101,   2, 132,  32}, {132,   2, 163,  32},
+    {  0,  32,  31,  62},
+  }, },
+  { {0, 0, 672, 64}, {194, 30}, 7, {
+    {  0,   0,  31,  30}, { 31,   0,  62,  30}, { 62,   0,  70,  30},
+    { 70,   0, 101,  30}, {101,   0, 132,  30}, {132,   0, 163,  30},
+    {  0,  30,  31,  60},
+  }, },
+  { {0, 0, 124, 226}, {31, 188}, 7, {
+    {  0,   0,  31,  30}, { 31,   0,  62,  30}, {  0,  30, 124,  38},
+    {  0,  38,  31,  68}, { 31,  38,  62,  68}, { 62,  38,  93,  68},
+    { 93,  38, 124,  68},
+  }, },
+  { {0, 0, 672, 26}, {146, 22}, 7, {
+    {  0,   2,  23,  24}, { 23,   2,  46,  24}, { 46,   2,  54,  24},
+    { 54,   2,  77,  24}, { 77,   2, 100,  24}, {100,   2, 123,  24},
+    {123,   2, 146,  24},
+  }, },
+  { {0, 0, 672, 26}, {146, 100}, 7, {
+    {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
+    { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
+    {123,   0, 146, 100},
+  }, },
+  { {0, 0, 672, 26}, {215, 100}, 10, {
+    {  0,   0,  23, 100}, { 23,   0,  46, 100}, { 46,   0,  54, 100},
+    { 54,   0,  77, 100}, { 77,   0, 100, 100}, {100,   0, 123, 100},
+    {123,   0, 146, 100}, {146,   0, 169, 100}, {169,   0, 192, 100},
+    {192,   0, 215, 100},
+  }, },
+  { {0, 0, 672, 26}, {238, 39}, 11, {
+    {  0,   0,  23,  39}, { 23,   0,  46,  39}, { 46,   0,  54,  39},
+    { 54,   0,  77,  39}, { 77,   0, 100,  39}, {100,   0, 123,  39},
+    {123,   0, 146,  39}, {146,   0, 169,  39}, {169,   0, 192,  39},
+    {192,   0, 215,  39}, {215,   0, 238,  39},
+  }, },
+  { {0, 0, 672, 26}, {238, 22}, 11, {
+    {  0,   0,  23,  22}, { 23,   0,  46,  22}, { 46,   0,  54,  22},
+    { 54,   0,  77,  22}, { 77,   0, 100,  22}, {100,   0, 123,  22},
+    {123,   0, 146,  22}, {146,   0, 169,  22}, {169,   0, 192,  22},
+    {192,   0, 215,  22}, {215,   0, 238,  22},
+  }, },
+  { {0, 0, 672, 26}, {489, 39}, 3, {
+    {  0,   2, 163,  41}, {163,   2, 330,  41}, {330,   2, 493,  41},
+  }, },
+  { {0, 0, 672, 104}, {978, 24}, 6, {
+    {  0,   2, 163,  26}, {163,   2, 326,  26}, {326,   2, 489,  26},
+    {489,   2, 652,  26}, {652,   2, 819,  26}, {819,   2, 850,  26},
+  }, },
+  { {0, 0, 672, 28}, {978, 38}, 6, {
+    {  0,   0, 163,  38}, {163,   0, 326,  38}, {326,   0, 489,  38},
+    {489,   0, 652,  38}, {652,   0, 819,  38}, {819,   0, 850,  38},
+  }, },
+};
+
+static int tbsize_numtests = 0;
+
+#define check_sizes_todo(todomask) { \
+        RECT rc; \
+        int buttonCount, i, mask=(todomask); \
+        tbsize_result_t *res = &tbsize_results[tbsize_numtests]; \
+        assert(tbsize_numtests < sizeof(tbsize_results)/sizeof(tbsize_results[0])); \
+        GetClientRect(hToolbar, &rc); \
+        /*check_rect("client", rc, res->rcClient);*/ \
+        buttonCount = SendMessage(hToolbar, TB_BUTTONCOUNT, 0, 0); \
+        compare(buttonCount, res->nButtons, "%d"); \
+        for (i=0; i<min(buttonCount, res->nButtons); i++) { \
+            ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \
+            if (!(mask&1)) { \
+                check_rect("button", rc, res->rcButtons[i]); \
+            } else {\
+                todo_wine { check_rect("button", rc, res->rcButtons[i]); } \
+            } \
+            mask >>= 1; \
+        } \
+        tbsize_numtests++; \
     }
-    return 0L;
+
+#define check_sizes() check_sizes_todo(0)
+
+#endif
+
+static TBBUTTON buttons1[] = {
+    {0, 10, TBSTATE_WRAP|TBSTATE_ENABLED, 0, {0, }, 0, -1},
+    {0, 11, 0, 0, {0, }, 0, -1},
+};
+static TBBUTTON buttons2[] = {
+    {0, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
+    {0, 21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
+};
+static TBBUTTON buttons3[] = {
+    {0, 30, TBSTATE_ENABLED, 0, {0, }, 0, 0},
+    {0, 31, TBSTATE_ENABLED, 0, {0, }, 0, 1},
+    {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1},
+    {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)"Tst"}
+};
+
+static void test_sizes(void)
+{
+    HWND hToolbar = NULL;
+    HIMAGELIST himl;
+    int style;
+    int i;
+
+    rebuild_toolbar_with_buttons(&hToolbar);
+    style = GetWindowLong(hToolbar, GWL_STYLE);
+    ok(style == (WS_CHILD|WS_VISIBLE|CCS_TOP), "Invalid style %x\n", style);
+    check_sizes();
+    /* the TBSTATE_WRAP makes a second row */
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
+    check_sizes();
+    SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
+    check_sizes();
+    /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */
+    SetWindowLong(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE);
+    check_sizes();
+    /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
+    check_sizes();
+    /* only after adding enough buttons the bar will be wrapped on a
+     * separator and then on the first button */
+    for (i=0; i<15; i++)
+        SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
+    check_sizes_todo(0x4);
+
+    rebuild_toolbar_with_buttons(&hToolbar);
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
+    /* setting the buttons vertical will only change the window client size */
+    SetWindowLong(hToolbar, GWL_STYLE, style | CCS_VERT);
+    SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
+    check_sizes_todo(0x3c);
+    /* with a TBSTYLE_WRAPABLE a wrapping will occur on the separator */
+    SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE | CCS_VERT);
+    SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
+    check_sizes_todo(0x7c);
+
+    rebuild_toolbar_with_buttons(&hToolbar);
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons1);
+    /* a TB_SETBITMAPSIZE changes button sizes*/
+    SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
+    check_sizes();
+
+    /* setting a TBSTYLE_FLAT doesn't change anything - even after a TB_AUTOSIZE */
+    SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
+    SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
+    check_sizes();
+    /* but after a TB_SETBITMAPSIZE the top margins is changed */
+    SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(20, 20));
+    SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24, 24));
+    check_sizes();
+    /* some vertical toolbar sizes */
+    SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | CCS_VERT);
+    check_sizes_todo(0x7c);
+
+    rebuild_toolbar_with_buttons(&hToolbar);
+    SetWindowLong(hToolbar, GWL_STYLE, style | TBSTYLE_FLAT);
+    /* newly added buttons will be use the previous margin */
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
+    check_sizes();
+    /* TB_SETBUTTONSIZE can't be used to reduce the size of a button below the default */
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(22, 21))==1, "TB_SETBUTTONSIZE\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3))==1, "TB_SETBUTTONSIZE\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(5, 100))==1, "TB_SETBUTTONSIZE\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 100), "Unexpected button size\n");
+    check_sizes();
+    /* add some buttons with non-default sizes */
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons2);
+    SendMessageA(hToolbar, TB_INSERTBUTTON, -1, (LPARAM)&buttons2[0]);
+    check_sizes();
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
+    /* TB_ADDSTRING resets the size */
+    SendMessageA(hToolbar, TB_ADDSTRING, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
+    check_sizes();
+    /* TB_SETBUTTONSIZE can be used to crop the text */
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+    check_sizes();
+    /* the default size is bitmap size + padding */
+    SendMessageA(hToolbar, TB_SETPADDING, 0, MAKELONG(1, 1));
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(17, 17), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(3, 3));
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(3, 3));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(4, 4), "Unexpected button size\n");
+
+    rebuild_toolbar(&hToolbar);
+    /* sending a TB_SETBITMAPSIZE with the same sizes is enough to make the button smaller */
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 21), "Unexpected button size\n");
+
+    rebuild_toolbar(&hToolbar);
+    SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
+    /* the height is increased after a TB_ADDSTRING */
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 39), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
+    /* if a string is in the pool, even adding a button without a string resets the size */
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
+    /* an BTNS_AUTOSIZE button is also considered when computing the new size */
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]);
+    check_sizes();
+    /* delete button doesn't change the buttons size */
+    SendMessageA(hToolbar, TB_DELETEBUTTON, 2, 0);
+    SendMessageA(hToolbar, TB_DELETEBUTTON, 1, 0);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 39), "Unexpected button size\n");
+    /* TB_INSERTBUTTONS will */
+    SendMessageA(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons2[0]);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+
+    /* TB_HIDEBUTTON and TB_MOVEBUTTON doesn't force a recalc */
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
+    ok(SendMessageA(hToolbar, TB_MOVEBUTTON, 0, 1), "TB_MOVEBUTTON failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_HIDEBUTTON, 20, TRUE), "TB_HIDEBUTTON failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
+    /* however changing the hidden flag with TB_SETSTATE does */
+    ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED|TBSTATE_HIDDEN), "TB_SETSTATE failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETSTATE, 20, TBSTATE_ENABLED), "TB_SETSTATE failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n");
+
+    /* TB_SETIMAGELIST always changes the height but the width only if necessary */
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
+    himl = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_80x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR);
+    ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 21), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 7), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1));
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(8, 7), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n");
+    /* the text is taken into account */
+    SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0");
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 4, (LPARAM)buttons3);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 38), "Unexpected button size\n");
+    ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n");
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(163, 24), "Unexpected button size\n");
+    /* the style change also comes into effect */
+    check_sizes();
+    SetWindowLong(hToolbar, GWL_STYLE, GetWindowLong(hToolbar, GWL_STYLE) | TBSTYLE_FLAT);
+    ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LPARAM)himl) == 0, "TB_SETIMAGELIST failed\n");
+    check_sizes_todo(0x30);     /* some small problems with BTNS_AUTOSIZE button sizes */
+
+    rebuild_toolbar(&hToolbar);
+    ImageList_Destroy(himl);
+
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
+    SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0);
+    ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
+
+    DestroyWindow(hToolbar);
+}
+
+static void test_getbuttoninfo(void)
+{
+    HWND hToolbar = NULL;
+    int i;
+
+    rebuild_toolbar_with_buttons(&hToolbar);
+    for (i = 0; i < 128; i++)
+    {
+        TBBUTTONINFO tbi;
+        int ret;
+
+        tbi.cbSize = i;
+        tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
+        ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi);
+        if (i == sizeof(TBBUTTONINFO)) {
+            compare(ret, 0, "%d");
+        } else {
+            compare(ret, -1, "%d");
+        }
+    }
+    DestroyWindow(hToolbar);
+}
+
+static void test_createtoolbarex(void)
+{
+    HWND hToolbar;
+    TBBUTTON btns[3];
+    ZeroMemory(&btns, sizeof(btns));
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, 20, 20, 16, 16, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(16, 20, 20);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x1a001b, "%x");
+    DestroyWindow(hToolbar);
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, 4, 4, 16, 16, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(32, 4, 4);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xa000b, "%x");
+    DestroyWindow(hToolbar);
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, 0, 8, 12, 12, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(16, 12, 12);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x120013, "%x");
+    DestroyWindow(hToolbar);
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, -1, 8, 12, 12, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(16, 12, 8);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0013, "%x");
+    DestroyWindow(hToolbar);
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, -1, 8, -1, 12, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(16, 16, 8);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0xe0017, "%x");
+    DestroyWindow(hToolbar);
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, 0, 0, 12, -1, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(16, 12, 16);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160013, "%x");
+    DestroyWindow(hToolbar);
+
+    hToolbar = CreateToolbarEx(hMainWnd, WS_VISIBLE, 1, 16, GetModuleHandle(NULL), IDB_BITMAP_128x15, btns,
+        3, 0, 0, 0, 12, sizeof(TBBUTTON));
+    CHECK_IMAGELIST(16, 16, 16);
+    compare((int)SendMessage(hToolbar, TB_GETBUTTONSIZE, 0, 0), 0x160017, "%x");
+    DestroyWindow(hToolbar);
+}
+
+static void test_dispinfo(void)
+{
+    HWND hToolbar = NULL;
+    const TBBUTTON buttons_disp[] = {
+        {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
+        {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
+    };
+    BOOL ret;
+
+    rebuild_toolbar(&hToolbar);
+    SendMessageA(hToolbar, TB_LOADIMAGES, IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp);
+    g_dwExpectedDispInfoMask = 1;
+    /* Some TBN_GETDISPINFO tests will be done in MyWnd_Notify function.
+     * We will receive TBN_GETDISPINFOW even if the control is ANSI */
+    compare((BOOL)SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0, "%d");
+    ShowWindow(hToolbar, SW_SHOW);
+    UpdateWindow(hToolbar);
+
+    ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, TRUE, 0);
+    compare(ret, FALSE, "%d");
+    compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 1L, "%ld");
+    InvalidateRect(hToolbar, NULL, FALSE);
+    UpdateWindow(hToolbar);
+
+    ret = (BOOL)SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0);
+    compare(ret, TRUE, "%d");
+    compare(SendMessageA(hToolbar, CCM_GETUNICODEFORMAT, 0, 0), 0L, "%ld");
+    InvalidateRect(hToolbar, NULL, FALSE);
+    UpdateWindow(hToolbar);
+
+    DestroyWindow(hToolbar);
+    g_dwExpectedDispInfoMask = 0;
+}
+
+typedef struct
+{
+    int  nRows;
+    BOOL bLarger;
+    int  expectedRows;
+} tbrows_result_t;
+
+static tbrows_result_t tbrows_results[] =
+{
+    {1, TRUE,  1}, /* 0: Simple case 9 in a row */
+    {2, TRUE,  2}, /* 1: Another simple case 5 on one row, 4 on another*/
+    {3, FALSE, 3}, /* 2: 3 lines - should be 3 lines of 3 buttons */
+    {8, FALSE, 5}, /* 3: 8 lines - should be 5 lines of 2 buttons */
+    {8, TRUE,  9}, /* 4: 8 lines but grow - should be 9 lines */
+    {1, TRUE,  1}  /* 5: Back to simple case */
+};
+
+static void test_setrows(void)
+{
+    TBBUTTON buttons[9];
+    HWND hToolbar;
+    int i;
+
+    for (i=0; i<9; i++)
+        MakeButton(buttons+i, 1000+i, TBSTYLE_FLAT | TBSTYLE_CHECKGROUP, 0);
+
+    /* Test 1 - 9 buttons */
+    hToolbar = CreateToolbarEx(hMainWnd,
+        WS_VISIBLE | WS_CLIPCHILDREN | WS_CHILD | CCS_NORESIZE | CCS_NOPARENTALIGN
+        | CCS_NOMOVEY | CCS_TOP,
+        0,
+        0, NULL, (UINT)0,
+        buttons, sizeof(buttons)/sizeof(buttons[0]),
+        20, 20, 0, 0, sizeof(TBBUTTON));
+    ok(hToolbar != NULL, "Toolbar creation\n");
+    ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
+
+    /* test setting rows to each of 1-10 with bLarger true and false */
+    for (i=0; i<(sizeof(tbrows_results) / sizeof(tbrows_result_t)); i++) {
+        RECT rc;
+        int rows;
+
+        memset(&rc, 0xCC, sizeof(rc));
+        SendMessageA(hToolbar, TB_SETROWS,
+                     MAKELONG(tbrows_results[i].nRows, tbrows_results[i].bLarger),
+                     (LONG) &rc);
+
+        rows = SendMessageA(hToolbar, TB_GETROWS, MAKELONG(0,0), MAKELONG(0,0));
+        ok(rows == tbrows_results[i].expectedRows,
+                   "[%d] Unexpected number of rows %d (expected %d)\n", i, rows,
+                   tbrows_results[i].expectedRows);
+    }
+
+    DestroyWindow(hToolbar);
 }
 
 START_TEST(toolbar)
@@ -110,28 +1093,40 @@ START_TEST(toolbar)
     WNDCLASSA wc;
     MSG msg;
     RECT rc;
-    HWND hMainWnd;
-
+  
     InitCommonControls();
-
+  
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
     wc.hInstance = GetModuleHandleA(NULL);
     wc.hIcon = NULL;
-    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
+    wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
     wc.lpszClassName = "MyTestWnd";
     wc.lpfnWndProc = MyWndProc;
     RegisterClassA(&wc);
-
-    hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
+    
+    hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
     GetClientRect(hMainWnd, &rc);
+    ShowWindow(hMainWnd, SW_SHOW);
+
+    basic_test();
+    test_add_bitmap();
+    test_add_string();
+    test_hotitem();
+    test_sizes();
+    test_getbuttoninfo();
+    test_createtoolbarex();
+    test_dispinfo();
+    test_setrows();
 
+    PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
         TranslateMessage(&msg);
         DispatchMessageA(&msg);
     }
+    DestroyWindow(hMainWnd);
 }
index 7f32471..713fa24 100644 (file)
@@ -38,10 +38,10 @@ static void test_create_tooltip(void)
     assert(hwnd);
 
     style = GetWindowLong(hwnd, GWL_STYLE);
-    trace("style = %08lx\n", style);
+    trace("style = %08x\n", style);
     exp_style = 0x7fffffff | WS_POPUP;
     exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
-    ok(style == exp_style,"wrong style %08lx/%08lx\n", style, exp_style);
+    ok(style == exp_style,"wrong style %08x/%08x\n", style, exp_style);
 
     DestroyWindow(hwnd);
 
@@ -51,9 +51,9 @@ static void test_create_tooltip(void)
     assert(hwnd);
 
     style = GetWindowLong(hwnd, GWL_STYLE);
-    trace("style = %08lx\n", style);
+    trace("style = %08x\n", style);
     ok(style == (WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER),
-       "wrong style %08lx\n", style);
+       "wrong style %08x\n", style);
 
     DestroyWindow(hwnd);
 
diff --git a/rostests/winetests/comctl32/trackbar.c b/rostests/winetests/comctl32/trackbar.c
new file mode 100644 (file)
index 0000000..13f56fd
--- /dev/null
@@ -0,0 +1,1012 @@
+/* Unit tests for the track bar control.
+ *
+ * Copyright 2007 Keith Stevens
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "msg.h"
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+#define NUM_MSG_SEQUENCE 2
+#define PARENT_SEQ_INDEX 0
+#define TRACKBAR_SEQ_INDEX 1
+
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCE];
+
+static const struct message create_parent_wnd_seq[] = {
+    { WM_GETMINMAXINFO, sent },
+    { WM_NCCREATE, sent },
+    { WM_NCCALCSIZE, sent|wparam, 0 },
+    { WM_CREATE, sent },
+    { WM_SHOWWINDOW, sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|defwinproc|optional },
+    { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    /* Win9x adds SWP_NOZORDER below */
+    { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+    { WM_SIZE, sent },
+    { WM_MOVE, sent },
+    { 0 }
+};
+
+static const struct message create_trackbar_wnd_seq[] = {
+    {0}
+};
+
+static const struct message parent_empty_test_seq[] = {
+    {0}
+};
+
+static const struct message parent_create_trackbar_wnd_seq[] = {
+    { WM_NOTIFYFORMAT, sent},
+    { 0x0129, sent}, /* should be WM_QUERYUISTATE instead of 0x0129 */
+    { WM_WINDOWPOSCHANGING, sent},
+    { WM_NCACTIVATE, sent},
+    { PBT_APMRESUMECRITICAL, sent},
+    { WM_WINDOWPOSCHANGING, sent},
+    { PBT_APMRESUMESTANDBY, sent},
+    { WM_IME_SETCONTEXT, sent|optional},
+    { WM_IME_NOTIFY, sent|optional},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message parent_new_window_test_seq[] = {
+    { WM_WINDOWPOSCHANGING, sent},
+    { WM_NCACTIVATE, sent},
+    { PBT_APMRESUMECRITICAL, sent},
+    { WM_IME_SETCONTEXT, sent|defwinproc|optional},
+    { WM_IME_NOTIFY, sent|defwinproc|optional},
+    { WM_SETFOCUS, sent|defwinproc},
+    { WM_NOTIFYFORMAT, sent},
+    { 0x0129, sent}, /* should be WM_QUERYUISTATE instead of 0x0129*/
+    {0}
+};
+
+static const struct message buddy_window_test_seq[] = {
+    { TBM_GETBUDDY, sent|wparam, TRUE},
+    { TBM_SETBUDDY, sent|wparam, FALSE},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_SETBUDDY, sent|wparam, FALSE},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETBUDDY, sent|wparam, TRUE},
+    { TBM_SETBUDDY, sent|wparam, TRUE},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_SETBUDDY, sent|wparam, TRUE},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETBUDDY, sent|wparam, FALSE},
+    { TBM_GETBUDDY, sent|wparam, TRUE},
+    {0}
+};
+
+static const struct message parent_buddy_window_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message line_size_test_seq[] = {
+    { TBM_SETLINESIZE, sent|lparam, 0, 10},
+    { TBM_SETLINESIZE, sent|lparam, 0, 4},
+    { TBM_GETLINESIZE, sent},
+    {0}
+};
+
+static const struct message page_size_test_seq[] = {
+    { TBM_SETPAGESIZE, sent|lparam, 0, 10},
+    { TBM_SETPAGESIZE, sent|lparam, 0, -1},
+    { TBM_GETPAGESIZE, sent},
+    {0}
+};
+
+static const struct message position_test_seq[] = {
+    { TBM_SETPOS, sent|wparam|lparam, TRUE, -1},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETPOS, sent},
+    { TBM_SETPOS, sent|wparam|lparam, TRUE, 5},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETPOS, sent},
+    { TBM_SETPOS, sent|wparam|lparam, TRUE, 1000},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETPOS, sent},
+    { TBM_SETPOS, sent|wparam|lparam, FALSE, 20},
+    { TBM_GETPOS, sent},
+    { TBM_GETPOS, sent},
+    {0}
+};
+
+static const struct message parent_position_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message range_test_seq[] = {
+    { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(0, 10)},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(-1, 1000)},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(10, 0)},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGE, sent|wparam|lparam, FALSE, MAKELONG(0, 10)},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGEMAX, sent|wparam|lparam, TRUE, 10},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_SETRANGEMAX, sent|wparam|lparam, TRUE, -1},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_SETRANGEMAX, sent|wparam|lparam, FALSE, 10},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_SETRANGEMIN, sent|wparam|lparam, TRUE, 0},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGEMIN, sent|wparam|lparam, TRUE, 10},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGEMIN, sent|wparam|lparam, TRUE, -10},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_SETRANGEMIN, sent|wparam|lparam, FALSE, 5},
+    { TBM_GETRANGEMIN, sent},
+    { TBM_GETRANGEMAX, sent},
+    { TBM_GETRANGEMIN, sent},
+    {0}
+};
+
+static const struct message parent_range_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message selection_test_seq[] = {
+    { TBM_SETSEL, sent|wparam|lparam, TRUE, MAKELONG(0, 10)},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELEND, sent},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSEL, sent|wparam|lparam, TRUE, MAKELONG(5, 20)},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELEND, sent},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSEL, sent|wparam|lparam, FALSE, MAKELONG(5, 10)},
+    { TBM_GETSELEND, sent},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, TRUE, 10},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, TRUE, 20},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, TRUE, 4},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, FALSE, 2},
+    { TBM_GETSELEND, sent},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 5},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 0},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 20},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, FALSE, 8},
+    { TBM_GETSELSTART, sent},
+    { TBM_GETSELSTART, sent},
+    {0}
+};
+
+static const struct message parent_selection_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message tic_settings_test_seq[] = {
+    { TBM_SETTIC, sent|lparam, 0, 0},
+    { TBM_SETTIC, sent|lparam, 0, 5},
+    { TBM_SETTIC, sent|lparam, 0, 10},
+    { TBM_SETTIC, sent|lparam, 0, 20},
+    { TBM_SETRANGE, sent|wparam|lparam, TRUE, MAKELONG(0,10)},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_SETTICFREQ, sent|wparam, 2},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETNUMTICS, sent},
+    { TBM_SETTICFREQ, sent|wparam, 5},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETNUMTICS, sent},
+    { TBM_SETTICFREQ, sent|wparam, 15},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETNUMTICS, sent},
+    { TBM_GETNUMTICS, sent},
+    {0}
+};
+
+static const struct message parent_tic_settings_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message thumb_length_test_seq[] = {
+    { TBM_SETTHUMBLENGTH, sent|wparam|lparam, 15, 0},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETTHUMBLENGTH, sent},
+    { TBM_SETTHUMBLENGTH, sent|wparam|lparam, 20, 0},
+    { WM_PAINT, sent|defwinproc},
+    { TBM_GETTHUMBLENGTH, sent},
+    { TBM_GETTHUMBLENGTH, sent},
+    {0}
+};
+
+static const struct message parent_thumb_length_test_seq[] = {
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    { WM_CTLCOLORSTATIC, sent},
+    { WM_NOTIFY, sent},
+    {0}
+};
+
+static const struct message tic_placement_test_seq[] = {
+    { TBM_GETPTICS, sent},
+    { TBM_GETTIC, sent|wparam, 0},
+    { TBM_GETTIC, sent|wparam, 4},
+    { TBM_GETTIC, sent|wparam, 11},
+    { TBM_GETTICPOS, sent|wparam, 0},
+    { TBM_GETTICPOS, sent|wparam, 4},
+    {0}
+};
+
+static const struct message tool_tips_test_seq[] = {
+    { TBM_SETTIPSIDE, sent|wparam, TBTS_TOP},
+    { TBM_SETTIPSIDE, sent|wparam, TBTS_LEFT},
+    { TBM_SETTIPSIDE, sent|wparam, TBTS_BOTTOM},
+    { TBM_SETTIPSIDE, sent|wparam, TBTS_RIGHT},
+    { TBM_SETTOOLTIPS, sent},
+    { TBM_GETTOOLTIPS, sent},
+    { TBM_SETTOOLTIPS, sent},
+    { TBM_GETTOOLTIPS, sent},
+    { TBM_SETTOOLTIPS, sent},
+    { TBM_GETTOOLTIPS, sent},
+    { TBM_GETTOOLTIPS, sent},
+    {0}
+};
+
+static const struct message unicode_test_seq[] = {
+    { TBM_SETUNICODEFORMAT, sent|wparam, TRUE},
+    { TBM_SETUNICODEFORMAT, sent|wparam, FALSE},
+    { TBM_GETUNICODEFORMAT, sent},
+    {0}
+};
+
+static const struct message ignore_selection_test_seq[] = {
+    { TBM_SETSEL, sent|wparam|lparam, TRUE, MAKELONG(0,10)},
+    { TBM_GETSELEND, sent},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSEL, sent|wparam|lparam, FALSE, MAKELONG(0,10)},
+    { TBM_GETSELEND, sent},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, TRUE,0},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, TRUE, 10},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELEND, sent|wparam|lparam, FALSE,0},
+    { TBM_GETSELEND, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, TRUE,0},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, TRUE, 10},
+    { TBM_GETSELSTART, sent},
+    { TBM_SETSELSTART, sent|wparam|lparam, FALSE,0},
+    { TBM_GETSELSTART, sent},
+    {0}
+};
+
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static BOOL register_parent_wnd_class(void){
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Trackbar test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND create_parent_window(void){
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindowEx(0, "Trackbar test parent class",
+        "Trackbar test parent window",
+        WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+        WS_MAXIMIZEBOX | WS_VISIBLE,
+        0, 0, 100, 100,
+        GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
+}
+
+static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
+    struct subclass_info *info = (struct subclass_info *) GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, TRACKBAR_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND create_trackbar(DWORD style, HWND parent){
+    struct subclass_info *info;
+    HWND hWndTrack;
+    RECT rect;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    GetClientRect(parent, &rect);
+    hWndTrack = CreateWindowEx(
+      0, TRACKBAR_CLASS,"Trackbar Control", style,
+      rect.right,rect.bottom, 100, 50,
+      parent, NULL,GetModuleHandleA(NULL) ,NULL);
+
+    if (!hWndTrack)
+    {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndTrack, GWLP_WNDPROC, (LONG_PTR)trackbar_subclass_proc);
+
+    SetWindowLongPtrA(hWndTrack, GWLP_USERDATA, (LONG_PTR)info);
+
+    return hWndTrack;
+}
+
+/* test functions for setters, getters, and sequences */
+
+static void test_trackbar_buddy(HWND hWndTrackbar){
+    HWND hWndLeftBuddy;
+    HWND hWndRightBuddy;
+    HWND hWndCurrentBuddy;
+    HWND rTest;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    hWndLeftBuddy = (HWND) CreateWindowEx(0, STATUSCLASSNAME, NULL, 0,
+        0,0,300,20, NULL, NULL, NULL, NULL);
+    ok(hWndLeftBuddy != NULL, "Expected non NULL value\n");
+
+    if (hWndLeftBuddy != NULL){
+        hWndCurrentBuddy = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, TRUE, 0);
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, FALSE, (LPARAM) hWndLeftBuddy);
+        ok(rTest == hWndCurrentBuddy, "Expected hWndCurrentBuddy\n");
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, FALSE, (LPARAM) hWndLeftBuddy);
+        ok(rTest == hWndLeftBuddy, "Expected hWndLeftBuddy\n");
+    } else
+        skip ("left buddy control not present?\n");
+
+    hWndRightBuddy = (HWND) CreateWindowEx(0, STATUSCLASSNAME, NULL, 0,
+        0,0,300,20,NULL,NULL, NULL, NULL);
+
+    ok(hWndRightBuddy != NULL, "expected non NULL value\n");
+
+    /* test TBM_SETBUDDY */
+    if (hWndRightBuddy != NULL){
+        hWndCurrentBuddy = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, TRUE, 0);
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, TRUE, (LPARAM) hWndRightBuddy);
+        ok(rTest == hWndCurrentBuddy, "Expected hWndCurrentBuddy\n");
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_SETBUDDY, TRUE, (LPARAM) hWndRightBuddy);
+        ok(rTest == hWndRightBuddy, "Expected hWndRightbuddy\n");
+     } else
+       skip("Right buddy control not present?\n");
+
+    /* test TBM_GETBUDDY */
+    if (hWndLeftBuddy != NULL){
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, FALSE, 0);
+        ok(rTest == hWndLeftBuddy, "Expected hWndLeftBuddy\n");
+        DestroyWindow(hWndLeftBuddy);
+    }
+    if (hWndRightBuddy != NULL){
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETBUDDY, TRUE,0);
+        ok(rTest == hWndRightBuddy, "Expected hWndRightBuddy\n");
+        DestroyWindow(hWndRightBuddy);
+    }
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, buddy_window_test_seq, "buddy test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_buddy_window_test_seq, "parent buddy test seq", TRUE);
+
+}
+
+static void test_line_size(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    /* test TBM_SETLINESIZE */
+    r = SendMessage(hWndTrackbar, TBM_SETLINESIZE, 0, 10);
+    r = SendMessage(hWndTrackbar, TBM_SETLINESIZE, 0, 4);
+    expect(10, r);
+
+    /* test TBM_GETLINESIZE */
+    r = SendMessage(hWndTrackbar, TBM_GETLINESIZE, 0,0);
+    expect(4, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, line_size_test_seq, "linesize test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent line test sequence", FALSE);
+}
+
+
+static void test_page_size(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    /* test TBM_SETPAGESIZE */
+    r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, 10);
+    expect(20, r);
+    r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, -1);
+    expect(10, r);
+
+    /* test TBM_GETPAGESIZE */
+    r = SendMessage(hWndTrackbar, TBM_GETPAGESIZE, 0,0);
+    todo_wine{
+        expect(20, r);
+    }
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, page_size_test_seq, "page size test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent page size test sequence", FALSE);
+}
+
+static void test_position(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* test TBM_SETPOS */
+    SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, -1);
+    r = SendMessage(hWndTrackbar, TBM_GETPOS, 0, 0);
+    expect(0, r);
+    SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 5);
+    r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0);
+    expect(5, r);
+    SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 1000);
+    r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0);
+    expect(100, r);
+    SendMessage(hWndTrackbar, TBM_SETPOS, FALSE, 20);
+    r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0);
+    expect(20, r);
+
+    /* test TBM_GETPOS */
+    r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0);
+    expect(20, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, position_test_seq, "position test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_position_test_seq, "parent position test sequence", TRUE);
+}
+
+static void test_range(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* test TBM_SETRANGE */
+    SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(0, 10));
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(10, r);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(0, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(-1, 1000));
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(1000, r);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(-1, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(10, 0));
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(0, r);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(10, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGE, FALSE, MAKELONG(0,10));
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(10, r);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(0, r);
+
+    /*test TBM_SETRANGEMAX */
+    SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 10);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(10, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, -1);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(-1, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMAX, FALSE, 10);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(10, r);
+
+    /* testing TBM_SETRANGEMIN */
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(0, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 10);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(10, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, -10);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(-10, r);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, FALSE, 5);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(5, r);
+
+    /* test TBM_GETRANGEMAX */
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMAX, 0,0);
+    expect(10, r);
+
+    /* test TBM_GETRANGEMIN */
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0,0);
+    expect(5, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, range_test_seq, "range test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_range_test_seq, "parent range test sequence", TRUE);
+}
+
+static void test_selection(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* test TBM_SETSEL */
+    SendMessage(hWndTrackbar, TBM_SETSEL, TRUE, MAKELONG(0,10));
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(10, r);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(5, r);
+    SendMessage(hWndTrackbar, TBM_SETSEL, TRUE, MAKELONG(5, 20));
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(10, r);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(5, r);
+    SendMessage(hWndTrackbar, TBM_SETSEL, FALSE, MAKELONG(5, 10));
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(10, r);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(5, r);
+
+    /* test TBM_SETSELEND */
+    SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 10);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(10, r);
+    SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 20);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(10, r);
+    SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 4);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(4, r);
+    SendMessage(hWndTrackbar, TBM_SETSELEND, FALSE, 2);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(2, r);
+
+    /* test TBM_GETSELEND */
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(2, r);
+
+    /* testing TBM_SETSELSTART */
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 5);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(5, r);
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(5, r);
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 20);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(20, r);
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, FALSE, 8);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(8, r);
+
+    /* test TBM_GETSELSTART */
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(8, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, selection_test_seq, "selection test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_selection_test_seq, "parent selection test seqence", TRUE);
+}
+
+static void test_thumb_length(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* testing TBM_SETTHUMBLENGTH */
+    SendMessage(hWndTrackbar, TBM_SETTHUMBLENGTH, 15, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0);
+    expect(15, r);
+    SendMessage(hWndTrackbar, TBM_SETTHUMBLENGTH, 20, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0);
+    expect(20, r);
+
+    /* test TBM_GETTHUMBLENGTH */
+    r = SendMessage(hWndTrackbar, TBM_GETTHUMBLENGTH, 0,0);
+    expect(20, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, thumb_length_test_seq, "thumb length test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_thumb_length_test_seq, "parent thumb lenth test sequence", TRUE);
+}
+
+static void test_tic_settings(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* testing TBM_SETTIC */
+    /* Set tics at 5 and 10 */
+    /* 0 and 20 are out of range and should not be set */
+    r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 0);
+    ok(r == FALSE, "Expected FALSE, got %d\n", r);
+    r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 5);
+    todo_wine{
+        ok(r == TRUE, "Expected TRUE, got %d\n", r);
+        r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 10);
+        ok(r == TRUE, "Expected TRUE, got %d\n", r);
+    }
+    r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 20);
+    ok(r == FALSE, "Expected False, got %d\n", r);
+
+    /* test TBM_SETTICFREQ */
+    SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(0, 10));
+    SendMessage(hWndTrackbar, TBM_SETTICFREQ, 2, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0);
+    expect(6, r);
+    SendMessage(hWndTrackbar, TBM_SETTICFREQ, 5, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0);
+    expect(3, r);
+    SendMessage(hWndTrackbar, TBM_SETTICFREQ, 15, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0);
+    expect(2, r);
+
+    /* test TBM_GETNUMTICS */
+    /* since TIC FREQ is 15, there should be only 2 tics now */
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0);
+    expect(2, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tic_settings_test_seq, "tic settings test sequence", TRUE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_tic_settings_test_seq, "parent tic settings test sequence", TRUE);
+}
+
+static void test_tic_placement(HWND hWndTrackbar){
+    int r;
+    DWORD *rPTics;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* test TBM_GETPTICS */
+    rPTics = (DWORD *) SendMessage(hWndTrackbar, TBM_GETPTICS, 0,0);
+    todo_wine{
+        expect(1, rPTics[0]);
+        expect(2, rPTics[1]);
+        expect(3, rPTics[2]);
+        expect(4, rPTics[3]);
+    }
+
+    /* test TBM_GETTIC */
+    r = SendMessage(hWndTrackbar, TBM_GETTIC, 0,0);
+    todo_wine{
+        expect(1, r);
+        r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0);
+        expect(5, r);
+    }
+    r = SendMessage(hWndTrackbar, TBM_GETTIC, 11,0);
+    expect(-1, r);
+
+    /* test TBM_GETTICPIC */
+    r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 0, 0);
+    todo_wine{
+        ok(r > 0, "Expected r > 0, got %d\n", r);
+        r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 4, 0);
+        ok(r > 0, "Expected r > 0, got %d\n", r);
+    }
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tic_placement_test_seq, "get tic placement test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent get tic placement test sequence", FALSE);
+}
+
+
+static void test_tool_tips(HWND hWndTrackbar){
+    int r;
+    HWND hWndTooltip;
+    HWND rTest;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* testing TBM_SETTIPSIDE */
+    r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_TOP, 0);
+    todo_wine{
+        expect(0, r);
+    }
+    r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_LEFT, 0);
+    expect(0, r);
+    r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_BOTTOM, 0);
+    expect(1, r);
+    r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_RIGHT, 0);
+    expect(2, r);
+
+    /* testing TBM_SETTOOLTIPS */
+    hWndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, 0,
+      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+      NULL, NULL, NULL, NULL);
+
+    ok(hWndTooltip != NULL, "Expected non NULL value\n");
+    if (hWndTooltip != NULL){
+        SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) hWndTooltip, 0);
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0);
+        ok(rTest == hWndTooltip, "Expected hWndToolTip, got\n");
+        SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) NULL, 0);
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0);
+        ok(rTest == NULL, "Expected NULL\n");
+        SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) hWndTooltip, 5);
+        rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0);
+        ok(rTest == hWndTooltip, "Expected hWndTooltip, got\n");
+    } else
+        skip("tool tip control not present?\n");
+
+    /* test TBM_GETTOOLTIPS */
+    rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0);
+    ok(rTest == hWndTooltip, "Expected hWndTooltip\n");
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tool_tips_test_seq, "tool tips test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent tool tips test sequence", FALSE);
+}
+
+
+static void test_unicode(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* testing TBM_SETUNICODEFORMAT */
+    r = SendMessage(hWndTrackbar, TBM_SETUNICODEFORMAT, TRUE, 0);
+    ok(r == FALSE, "Expected FALSE, got %d\n",r);
+    r = SendMessage(hWndTrackbar, TBM_SETUNICODEFORMAT, FALSE, 0);
+    ok(r == TRUE, "Expected TRUE, got %d\n",r);
+
+    /* test TBM_GETUNICODEFORMAT */
+    r = SendMessage(hWndTrackbar, TBM_GETUNICODEFORMAT, 0,0);
+    ok(r == FALSE, "Expected FALSE, got %d\n",r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, unicode_test_seq, "unicode test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent unicode test sequence", FALSE);
+}
+
+static void test_ignore_selection(HWND hWndTrackbar){
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    /* test TBM_SETSEL  ensure that it is ignored */
+    SendMessage(hWndTrackbar, TBM_SETSEL, TRUE, MAKELONG(0,10));
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(0, r);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(0, r);
+    SendMessage(hWndTrackbar, TBM_SETSEL, FALSE, MAKELONG(0,10));
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(0, r);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(0, r);
+
+    /* test TBM_SETSELEND, ensure that it is ignored */
+    SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(0, r);
+    SendMessage(hWndTrackbar, TBM_SETSELEND, TRUE, 10);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(0,r);
+    SendMessage(hWndTrackbar, TBM_SETSELEND, FALSE, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETSELEND, 0,0);
+    expect(0, r);
+
+    /* test TBM_SETSELSTART, ensure that it is ignored */
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(0, r);
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, TRUE, 10);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(0,r);
+    SendMessage(hWndTrackbar, TBM_SETSELSTART, FALSE, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETSELSTART, 0,0);
+    expect(0, r);
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, ignore_selection_test_seq, "ignore selection setting test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent ignore selection setting test sequence", FALSE);
+}
+
+START_TEST(trackbar)
+{
+    DWORD style = WS_VISIBLE | TBS_TOOLTIPS | TBS_ENABLESELRANGE | TBS_FIXEDLENGTH | TBS_AUTOTICKS;
+    HWND hWndTrackbar;
+    HWND hWndParent;
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCE);
+    InitCommonControls();
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    /* create parent window */
+    hWndParent = create_parent_window();
+    ok(hWndParent != NULL, "Failed to create parent Window!\n");
+
+    if(!hWndParent){
+        skip("parent window not present\n");
+        return;
+    }
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create Parent Window", TRUE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    /* create trackbar with set styles */
+    hWndTrackbar = create_trackbar(style, hWndParent);
+
+    ok(hWndTrackbar != NULL, "Expected non NULL value\n");
+
+    if (!hWndTrackbar){
+        skip("trackbar control not present?\n");
+        return;
+    }
+
+    ok_sequence(sequences, TRACKBAR_SEQ_INDEX, create_trackbar_wnd_seq, "create Trackbar Window", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_trackbar_wnd_seq, "parent trackbar window", TRUE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+
+    /* TEST OF ALL SETTER and GETTER MESSAGES with required styles turned on*/
+    test_trackbar_buddy(hWndTrackbar);
+    test_line_size(hWndTrackbar);
+    test_page_size(hWndTrackbar);
+    test_position(hWndTrackbar);
+    test_range(hWndTrackbar);
+    test_selection(hWndTrackbar);
+    test_thumb_length(hWndTrackbar);
+    test_tic_settings(hWndTrackbar);
+    test_tic_placement(hWndTrackbar);
+    test_tool_tips(hWndTrackbar);
+    test_unicode(hWndTrackbar);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
+    DestroyWindow(hWndTrackbar);
+
+    /* test getters and setters without styles set */
+    hWndTrackbar = create_trackbar(0, hWndParent);
+
+    ok(hWndTrackbar != NULL, "Expected non NULL value\n");
+
+    if (!hWndTrackbar){
+        skip("trackbar control not present?\n");
+        return;
+    }
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, parent_new_window_test_seq, "new trackbar window test sequence", TRUE);
+
+    test_ignore_selection(hWndTrackbar);
+
+    DestroyWindow(hWndTrackbar);
+
+    DestroyWindow(hWndParent);
+}
index d65155a..2981db7 100644 (file)
@@ -1,6 +1,7 @@
 /* Unit tests for treeview.
  *
  * Copyright 2005 Krzysztof Foltman
+ * Copyright 2007 Christopher James Peterson
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "winuser.h"
 #include "winnls.h"
 #include "winreg.h"
-#include "commctrl.h"
+#include "commctrl.h" 
 
 #include "wine/test.h"
+#include "msg.h"
+
+#define NUM_MSG_SEQUENCES   1
+#define LISTVIEW_SEQ_INDEX  0
+
+static struct msg_sequence *MsgSequences[NUM_MSG_SEQUENCES];
+
+static const struct message FillRootSeq[] = {
+    { TVM_INSERTITEM, sent },
+    { TVM_GETITEM, sent },
+    { TVM_INSERTITEM, sent },
+    { 0 }
+};
+
+static const struct message DoTest1Seq[] = {
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { 0 }
+};
+
+static const struct message DoTest2Seq[] = {
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    { 0 }
+};
+
+static const struct message DoFocusTestSeq[] = {
+    { TVM_INSERTITEM, sent },
+    { TVM_INSERTITEM, sent },
+    { WM_WINDOWPOSCHANGING, sent|defwinproc },
+    { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 },
+    { WM_WINDOWPOSCHANGED, sent|defwinproc },
+    { WM_SIZE, sent|defwinproc },
+    { WM_WINDOWPOSCHANGING, sent },
+    { WM_NCCALCSIZE, sent|wparam, 0x00000001 },
+    { WM_WINDOWPOSCHANGED, sent },
+    { WM_SIZE, sent|defwinproc },
+    { WM_WINDOWPOSCHANGING, sent|defwinproc },
+    { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 },
+    { WM_WINDOWPOSCHANGED, sent|defwinproc },
+    { WM_SIZE, sent|defwinproc },
+    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
+    /* The following end up out of order in wine */
+    { WM_PAINT, sent|defwinproc },
+    { WM_NCPAINT, sent|wparam|defwinproc, 0x00000001 },
+    { WM_ERASEBKGND, sent|defwinproc },
+    { TVM_EDITLABEL, sent },
+    { WM_COMMAND, sent|wparam|defwinproc, 0x04000000 },
+    { WM_COMMAND, sent|wparam|defwinproc, 0x03000000 },
+    { WM_PARENTNOTIFY, sent|wparam|defwinproc, 0x00000001 },
+    { WM_KILLFOCUS, sent|defwinproc },
+    { WM_PAINT, sent|defwinproc },
+    { WM_IME_SETCONTEXT, sent|defwinproc|optional },
+    { WM_COMMAND, sent|wparam|defwinproc, 0x01000000},
+    { WM_ERASEBKGND, sent|defwinproc },
+    { WM_CTLCOLOREDIT, sent|defwinproc|optional },
+    { WM_CTLCOLOREDIT, sent|defwinproc|optional },
+    { 0 }
+};
+
+static const struct message TestGetSetBkColorSeq[] = {
+    { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff },
+    { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0xffffffff },
+    { 0 }
+};
+
+static const struct message TestGetSetImageListSeq[] = {
+    { TVM_SETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message TestGetSetIndentSeq[] = {
+    { TVM_SETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    /* The actual amount to indent is dependent on the system for this message */
+    { TVM_SETINDENT, sent },
+    { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message TestGetSetInsertMarkColorSeq[] = {
+    { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message TestGetSetItemSeq[] = {
+    { TVM_GETITEM, sent },
+    { TVM_SETITEM, sent },
+    { TVM_GETITEM, sent },
+    { TVM_SETITEM, sent },
+    { 0 }
+};
+
+static const struct message TestGetSetItemHeightSeq[] = {
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETITEMHEIGHT, sent|wparam|lparam, 0xffffffff, 0x00000000 },
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0x00000000 },
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETITEMHEIGHT, sent|wparam|lparam, 0x00000009, 0x00000000 },
+    { WM_WINDOWPOSCHANGING, sent|defwinproc },
+    { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 },
+    { WM_WINDOWPOSCHANGED, sent|defwinproc },
+    { WM_SIZE, sent|defwinproc },
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message TestGetSetScrollTimeSeq[] = {
+    { TVM_SETSCROLLTIME, sent|wparam|lparam, 0x00000014, 0x00000000 },
+    { TVM_GETSCROLLTIME, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message TestGetSetTextColorSeq[] = {
+    { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff },
+    { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0xffffffff },
+    { 0 }
+};
+
+static const struct message TestGetSetToolTipsSeq[] = {
+    { WM_COMMAND,       sent|wparam,            0x02000000 },
+    { WM_PARENTNOTIFY,  sent|wparam|defwinproc, 0x00020002 },
+    { TVM_SETTOOLTIPS, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETTOOLTIPS, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
+
+static const struct message TestGetSetUnicodeFormatSeq[] = {
+    { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0x00000001, 0x00000000 },
+    { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { 0 }
+};
 
 static HWND hMainWnd;
 
-static HWND hTree;
+static HWND hTree, hEdit;
 static HTREEITEM hRoot, hChild;
 
 static int pos = 0;
@@ -70,6 +225,7 @@ static void IdentifyItem(HTREEITEM hItem)
 static void FillRoot(void)
 {
     TVINSERTSTRUCTA ins;
+    TVITEM tvi;
     static CHAR root[]  = "Root",
                 child[] = "Child";
 
@@ -82,6 +238,13 @@ static void FillRoot(void)
     hRoot = TreeView_InsertItem(hTree, &ins);
     assert(hRoot);
 
+    /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
+    tvi.hItem = hRoot;
+    tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+    SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+    ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
+    ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
+
     AddItem('B');
     ins.hParent = hRoot;
     ins.hInsertAfter = TVI_FIRST;
@@ -132,23 +295,326 @@ static void DoTest2(void)
     ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
 }
 
-LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+static void DoFocusTest(void)
+{
+    TVINSERTSTRUCTA ins;
+    static CHAR child1[]  = "Edit",
+                child2[]  = "A really long string";
+    HTREEITEM hChild1, hChild2;
+
+    /* This test verifies that when a label is being edited, scrolling
+     * the treeview does not cause the label to lose focus. To test
+     * this, first some additional entries are added to generate
+     * scrollbars.
+     */
+    ins.hParent = hRoot;
+    ins.hInsertAfter = hChild;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = child1;
+    hChild1 = TreeView_InsertItem(hTree, &ins);
+    assert(hChild1);
+    ins.hInsertAfter = hChild1;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = child2;
+    hChild2 = TreeView_InsertItem(hTree, &ins);
+    assert(hChild2);
+
+    ShowWindow(hMainWnd,SW_SHOW);
+    /* Using SendMessageA since Win98 doesn't have default unicode support */
+    SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
+    hEdit = TreeView_EditLabel(hTree, hChild);
+    ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
+    ok(GetFocus() == hEdit, "Edit control should have focus\n");
+}
+
+static void TestGetSetBkColor(void)
+{
+    COLORREF crColor = RGB(0,0,0);
+
+    todo_wine{
+        /* If the value is -1, the control is using the system color for the background color. */
+        crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
+        ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor);
+    }
+
+    /* Test for black background */
+    SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(0,0,0) );
+    crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
+    ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
+
+    /* Test for white background */
+    SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(255,255,255) );
+    crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 );
+    ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
+
+    /* Reset the default background */
+    SendMessage( hTree, TVM_SETBKCOLOR, 0, -1 );
+}
+
+static void TestGetSetImageList(void)
+{
+    HIMAGELIST hImageList = NULL;
+
+    /* Test a NULL HIMAGELIST */
+    SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
+    hImageList = (HIMAGELIST)SendMessage( hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0 );
+    ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
+
+    /* TODO: Test an actual image list */
+}
+
+static void TestGetSetIndent(void)
+{
+    int ulIndent = -1;
+    int ulMinIndent = -1;
+    int ulMoreThanTwiceMin = -1;
+
+    /* Finding the minimum indent */
+    SendMessage( hTree, TVM_SETINDENT, 0, 0 );
+    ulMinIndent = (int)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
+
+    /* Checking an indent that is more than twice the default indent */
+    ulMoreThanTwiceMin = 2*ulMinIndent+1;
+    SendMessage( hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0 );
+    ulIndent = (DWORD)SendMessage( hTree, TVM_GETINDENT, 0, 0 );
+    ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
+}
+
+static void TestGetSetInsertMarkColor(void)
+{
+    COLORREF crColor = RGB(0,0,0);
+    SendMessage( hTree, TVM_SETINSERTMARKCOLOR, 0, crColor );
+    crColor = (COLORREF)SendMessage( hTree, TVM_GETINSERTMARKCOLOR, 0, 0 );
+    ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
+}
+
+static void TestGetSetItem(void)
+{
+    TVITEM tviRoot = {0};
+    int nBufferSize = 80;
+    char szBuffer[80] = {0};
+
+    /* Test the root item */
+    tviRoot.hItem = hRoot;
+    tviRoot.mask = TVIF_TEXT;
+    tviRoot.cchTextMax = nBufferSize;
+    tviRoot.pszText = szBuffer;
+    SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
+    ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
+
+    /* Change the root text */
+    strncpy(szBuffer, "Testing123", nBufferSize);
+    SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
+    memset(szBuffer, 0, nBufferSize);
+    SendMessage( hTree, TVM_GETITEM, 0, (LPARAM)&tviRoot );
+    ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
+
+    /* Reset the root text */
+    memset(szBuffer, 0, nBufferSize);
+    strncpy(szBuffer, "Root", nBufferSize);
+    SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
+}
+
+static void TestGetSetItemHeight(void)
+{
+    int ulOldHeight = 0;
+    int ulNewHeight = 0;
+
+    /* Assuming default height to begin with */
+    ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
+
+    /* Explicitly setting and getting the default height */
+    SendMessage( hTree, TVM_SETITEMHEIGHT, -1, 0 );
+    ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
+    ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
+
+    /* Explicitly setting and getting the height of twice the normal */
+    SendMessage( hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0 );
+    ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
+    ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
+
+    /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
+    SendMessage( hTree, TVM_SETITEMHEIGHT, 9, 0 );
+    ulNewHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
+    ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
+}
+
+static void TestGetSetScrollTime(void)
+{
+    int ulExpectedTime = 20;
+    int ulTime = 0;
+    SendMessage( hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0 );
+    ulTime = (int)SendMessage( hTree, TVM_GETSCROLLTIME, 0, 0 );
+    ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
+}
+
+static void TestGetSetTextColor(void)
 {
+    /* If the value is -1, the control is using the system color for the text color. */
+    COLORREF crColor = RGB(0,0,0);
+    crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
+    ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor);
+
+    /* Test for black text */
+    SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(0,0,0) );
+    crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
+    ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
+
+    /* Test for white text */
+    SendMessage( hTree, TVM_SETTEXTCOLOR, 0, (LPARAM)RGB(255,255,255) );
+    crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
+    ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
+
+    /* Reset the default text color */
+    SendMessage( hTree, TVM_SETTEXTCOLOR, 0, -1 );
+}
+
+static void TestGetSetToolTips(void)
+{
+    HWND hwndLastToolTip = NULL;
+    HWND hPopupTreeView;
+
+    /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
+    hPopupTreeView = CreateWindow(WC_TREEVIEW, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL);
+    DestroyWindow(hPopupTreeView);
+
+    /* Testing setting a NULL ToolTip */
+    SendMessage( hTree, TVM_SETTOOLTIPS, 0, 0 );
+    hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
+    ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
+
+    /* TODO: Add a test of an actual tooltip */
+}
+
+static void TestGetSetUnicodeFormat(void)
+{
+    BOOL bPreviousSetting = 0;
+    BOOL bNewSetting = 0;
+
+    /* Set to Unicode */
+    bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
+    bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
+    ok(bNewSetting == 1, "Unicode setting did not work.\n");
+
+    /* Set to ANSI */
+    SendMessage( hTree, TVM_SETUNICODEFORMAT, 0, 0 );
+    bNewSetting = (BOOL)SendMessage( hTree, TVM_GETUNICODEFORMAT, 0, 0 );
+    ok(bNewSetting == 0, "ANSI setting did not work.\n");
+
+    /* Revert to original setting */
+    SendMessage( hTree, TVM_SETUNICODEFORMAT, (LPARAM)bPreviousSetting, 0 );
+}
+
+static void TestGetSet(void)
+{
+    /* TVM_GETBKCOLOR and TVM_SETBKCOLOR */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetBkColor();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetBkColorSeq,
+        "TestGetSetBkColor", FALSE);
+
+    /* TVM_GETIMAGELIST and TVM_SETIMAGELIST */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetImageList();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetImageListSeq,
+        "TestGetImageList", FALSE);
+
+    /* TVM_SETINDENT and TVM_GETINDENT */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetIndent();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetIndentSeq,
+        "TestGetSetIndent", FALSE);
+
+    /* TVM_GETINSERTMARKCOLOR and TVM_GETINSERTMARKCOLOR */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetInsertMarkColor();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetInsertMarkColorSeq,
+        "TestGetSetInsertMarkColor", FALSE);
+
+    /* TVM_GETITEM and TVM_SETITEM */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetItem();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetItemSeq,
+        "TestGetSetItem", FALSE);
+
+    /* TVM_GETITEMHEIGHT and TVM_SETITEMHEIGHT */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetItemHeight();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetItemHeightSeq,
+        "TestGetSetItemHeight", FALSE);
+
+    /* TVM_GETSCROLLTIME and TVM_SETSCROLLTIME */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetScrollTime();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetScrollTimeSeq,
+        "TestGetSetScrollTime", FALSE);
+
+    /* TVM_GETTEXTCOLOR and TVM_SETTEXTCOLOR */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetTextColor();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetTextColorSeq,
+        "TestGetSetTextColor", FALSE);
+
+    /* TVM_GETTOOLTIPS and TVM_SETTOOLTIPS */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetToolTips();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetToolTipsSeq,
+        "TestGetSetToolTips", TRUE);
+
+    /* TVM_GETUNICODEFORMAT and TVM_SETUNICODEFORMAT */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    TestGetSetUnicodeFormat();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, TestGetSetUnicodeFormatSeq,
+        "TestGetSetUnicodeFormat", FALSE);
+}
+
+/* This function hooks in and records all messages to the treeview control */
+static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+    WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(MsgSequences, LISTVIEW_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WNDPROC pOldWndProc;
+
     switch(msg) {
 
     case WM_CREATE:
     {
         hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
-            TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS,
-            0, 0, 300, 50, hWnd, (HMENU)100, GetModuleHandleA(0), 0);
+            TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS,
+            0, 0, 120, 100, hWnd, (HMENU)100, GetModuleHandleA(0), 0);
 
         SetFocus(hTree);
+
+        /* Record the old WNDPROC so we can call it after recording the messages */
+        pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
+        SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
+
         return 0;
     }
     case WM_NOTIFY:
     {
         NMHDR *pHdr = (NMHDR *)lParam;
-
+    
+        ok(pHdr->code != NM_FIRST - 19, "Treeview should not send NM_TOOLTIPSCREATED\n");
         if (pHdr->idFrom == 100) {
             NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
             switch(pHdr->code) {
@@ -166,15 +632,15 @@ LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
         }
         return 0;
     }
-
+  
     case WM_SIZE:
         MoveWindow(hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
         break;
-
+      
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
-
+  
     default:
         return DefWindowProcA(hWnd, msg, wParam, lParam);
     }
@@ -186,18 +652,18 @@ START_TEST(treeview)
     WNDCLASSA wc;
     MSG msg;
     INITCOMMONCONTROLSEX icex;
-    RECT rc;
-
+  
     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
     icex.dwICC   = ICC_TREEVIEW_CLASSES;
     InitCommonControlsEx(&icex);
-
+    init_msg_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+  
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
     wc.hInstance = GetModuleHandleA(NULL);
     wc.hIcon = NULL;
-    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
+    wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
     wc.lpszClassName = "MyTestWnd";
@@ -206,12 +672,29 @@ START_TEST(treeview)
 
 
     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
-      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
-    GetClientRect(hMainWnd, &rc);
+      CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
+
+    if ( !ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n") )
+        return;
 
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
     FillRoot();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
     DoTest1();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest1Seq, "DoTest1", FALSE);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
     DoTest2();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest2Seq, "DoTest2", FALSE);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+    DoFocusTest();
+    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoFocusTestSeq, "DoFocusTest", TRUE);
+
+    /* Sequences tested inside due to number */
+    TestGetSet();
 
     PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
     while(GetMessageA(&msg,0,0,0)) {
index c69657a..6f8e395 100644 (file)
@@ -1,6 +1,8 @@
-/* Unit test suite for updown control.
+/* Unit tests for the up-down control
  *
  * Copyright 2005 C. Scott Ananian
+ * Copyright (C) 2007 James Hawkins
+ * Copyright (C) 2007 Leslie Choong
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+/* TO TEST:
+ *   - send click messages to the up-down control, check the current position
+ *   - up-down control automatically positions itself next to its buddy window
+ *   - up-down control sets the caption of the buddy window
+ *   - test CreateUpDownControl API
+ *   - check UDS_AUTOBUDDY style, up-down control selects previous window in z-order
+ *   - check UDM_SETBUDDY message
+ *   - check UDM_GETBUDDY message
+ *   - up-down control and buddy control must have the same parent
+ *   - up-down control notifies its parent window when its position changes with UDN_DELTAPOS + WM_VSCROLL or WM_HSCROLL
+ *   - check UDS_ALIGN[LEFT,RIGHT]...check that width of buddy window is decreased
+ *   - check that UDS_SETBUDDYINT sets the caption of the buddy window when it is changed
+ *   - check that the thousands operator is set for large numbers
+ *   - check that the thousands operator is not set with UDS_NOTHOUSANDS
+ *   - check UDS_ARROWKEYS, control subclasses the buddy window so that it processes the keys when it has focus
+ *   - check UDS_HORZ
+ *   - check changing past min/max values
+ *   - check UDS_WRAP wraps values past min/max, incrementing past upper value wraps position to lower value
+ *   - can change control's position, min/max pos, radix
+ *   - check UDM_GETPOS, for up-down control with a buddy window, position is the caption of the buddy window, so change the
+ *     caption of the buddy window then call UDM_GETPOS
+ *   - check UDM_SETRANGE, max can be less than min, so clicking the up arrow decreases the current position
+ *   - more stuff to test
+ */
+
 #include <assert.h>
 #include <windows.h>
 #include <commctrl.h>
 #include <stdio.h>
 
 #include "wine/test.h"
+#include "msg.h"
+
+#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
+
+#define NUM_MSG_SEQUENCES   3
+#define PARENT_SEQ_INDEX    0
+#define EDIT_SEQ_INDEX      1
+#define UPDOWN_SEQ_INDEX    2
+
+static HWND parent_wnd, edit, updown;
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
+static const struct message create_parent_wnd_seq[] = {
+    { WM_GETMINMAXINFO, sent },
+    { WM_NCCREATE, sent },
+    { WM_NCCALCSIZE, sent|wparam, 0 },
+    { WM_CREATE, sent },
+    { WM_SHOWWINDOW, sent|wparam, 1 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
+    { WM_ACTIVATEAPP, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_ACTIVATE, sent|wparam, 1 },
+    { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
+    { WM_IME_NOTIFY, sent|defwinproc|optional },
+    { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
+    /* Win9x adds SWP_NOZORDER below */
+    { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
+    { WM_NCCALCSIZE, sent|wparam|optional, 1 },
+    { WM_SIZE, sent },
+    { WM_MOVE, sent },
+    { 0 }
+};
+
+static const struct message add_edit_to_parent_seq[] = {
+    { WM_PARENTNOTIFY, sent|wparam, WM_CREATE },
+    { 0 }
+};
+
+static const struct message add_updown_with_edit_seq[] = {
+    { WM_WINDOWPOSCHANGING, sent },
+    { WM_NCCALCSIZE, sent|wparam, TRUE },
+    { WM_WINDOWPOSCHANGED, sent },
+    { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED /*, MAKELONG(91, 75) exact size depends on font */ },
+    { 0 }
+};
+
+static const struct message add_updown_to_parent_seq[] = {
+    { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
+    { WM_QUERYUISTATE, sent },
+    { WM_PARENTNOTIFY, sent|wparam, MAKELONG(WM_CREATE, WM_CREATE) },
+    { 0 }
+};
+
+static const struct message get_edit_text_seq[] = {
+    { WM_GETTEXT, sent },
+    { 0 }
+};
+
+static const struct message test_updown_pos_seq[] = {
+    { UDM_SETRANGE, sent|lparam, 0, MAKELONG(100,0) },
+    { UDM_GETRANGE, sent},
+    { UDM_SETPOS, sent|lparam, 0, 5},
+    { UDM_GETPOS, sent},
+    { UDM_SETPOS, sent|lparam, 0, 0},
+    { UDM_GETPOS, sent},
+    { UDM_SETPOS, sent|lparam, 0, MAKELONG(-1,0)},
+    { UDM_GETPOS, sent},
+    { UDM_SETPOS, sent|lparam, 0, 100},
+    { UDM_GETPOS, sent},
+    { UDM_SETPOS, sent|lparam, 0, 101},
+    { UDM_GETPOS, sent},
+    { 0 }
+};
+
+static const struct message test_updown_pos32_seq[] = {
+    { UDM_SETRANGE32, sent|lparam, 0, 1000 },
+    { UDM_GETRANGE32, sent}, /* Cannot check wparam and lparam as they are ptrs */
+    { UDM_SETPOS32, sent|lparam, 0, 500 },
+    { UDM_GETPOS32, sent},
+    { UDM_SETPOS32, sent|lparam, 0, 0 },
+    { UDM_GETPOS32, sent},
+    { UDM_SETPOS32, sent|lparam, 0, -1 },
+    { UDM_GETPOS32, sent},
+    { UDM_SETPOS32, sent|lparam, 0, 1000 },
+    { UDM_GETPOS32, sent},
+    { UDM_SETPOS32, sent|lparam, 0, 1001 },
+    { UDM_GETPOS32, sent},
+    { 0 }
+};
+
+static const struct message test_updown_buddy_seq[] = {
+    { UDM_GETBUDDY, sent },
+    { UDM_SETBUDDY, sent },
+    { WM_STYLECHANGING, sent|defwinproc },
+    { WM_STYLECHANGED, sent|defwinproc },
+    { WM_STYLECHANGING, sent|defwinproc },
+    { WM_STYLECHANGED, sent|defwinproc },
+    { WM_WINDOWPOSCHANGING, sent|defwinproc },
+    { WM_NCCALCSIZE, sent|wparam|optional|defwinproc, 1 },
+    { WM_WINDOWPOSCHANGED, sent|defwinproc },
+    { WM_MOVE, sent|defwinproc },
+    { UDM_GETBUDDY, sent },
+    { 0 }
+};
+
+static const struct message test_updown_base_seq[] = {
+    { UDM_SETBASE, sent|wparam, 10 },
+    { UDM_GETBASE, sent },
+    { UDM_SETBASE, sent|wparam, 80 },
+    { UDM_GETBASE, sent },
+    { UDM_SETBASE, sent|wparam, 16 },
+    { UDM_GETBASE, sent },
+    { UDM_SETBASE, sent|wparam, 80 },
+    { UDM_GETBASE, sent },
+    { UDM_SETBASE, sent|wparam, 10 },
+    { UDM_GETBASE, sent },
+    { 0 }
+};
 
-static HDC desktopDC;
-static HINSTANCE hinst;
+static const struct message test_updown_unicode_seq[] = {
+    { UDM_SETUNICODEFORMAT, sent|wparam, 0 },
+    { UDM_GETUNICODEFORMAT, sent },
+    { UDM_SETUNICODEFORMAT, sent|wparam, 1 },
+    { UDM_GETUNICODEFORMAT, sent },
+    { UDM_SETUNICODEFORMAT, sent|wparam, 0 },
+    { UDM_GETUNICODEFORMAT, sent },
+    { 0 }
+};
 
-static HWND create_edit_control (DWORD style, DWORD exstyle)
+static const struct message test_updown_destroy_seq[] = {
+    { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0 },
+    { WM_WINDOWPOSCHANGING, sent},
+    { WM_WINDOWPOSCHANGED, sent},
+    { WM_DESTROY, sent},
+    { WM_NCDESTROY, sent},
+    { 0 }
+};
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-    HWND handle;
-
-    handle = CreateWindowEx(exstyle,
-                         "EDIT",
-                         NULL,
-                         ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
-                         10, 10, 300, 300,
-                         NULL, NULL, hinst, NULL);
-    assert (handle);
-    if (winetest_interactive)
-       ShowWindow (handle, SW_SHOW);
-    return handle;
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    /* do not log painting messages */
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+        msg.message = message;
+        msg.flags = sent|wparam|lparam;
+        if (defwndproc_counter) msg.flags |= defwinproc;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
 }
 
-static HWND create_updown_control (HWND hWndEdit)
+static BOOL register_parent_wnd_class(void)
 {
-    HWND hWndUpDown;
-
-    /* make the control */
-    hWndUpDown = CreateWindowEx
-       (0L, UPDOWN_CLASS, NULL,
-        /* window styles */
-        UDS_SETBUDDYINT | UDS_ALIGNRIGHT |
-        UDS_ARROWKEYS | UDS_NOTHOUSANDS,
-        /* placement */
-        0, 0, 8, 8,
-        /* parent, etc */
-        NULL, NULL, hinst, NULL);
-    assert (hWndUpDown);
-    /* set the buddy. */
-    SendMessage (hWndUpDown, UDM_SETBUDDY, (WPARAM)hWndEdit, 0L );
-    /* set the range. */
-    SendMessage (hWndUpDown, UDM_SETRANGE, 0L, (LPARAM) MAKELONG(32000, 0));
-    /* maybe show it. */
-    if (winetest_interactive)
-       ShowWindow (hWndUpDown, SW_SHOW);
-    return hWndUpDown;
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = parent_wnd_proc;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Up-Down test parent class";
+    return RegisterClassA(&cls);
 }
 
-static void test_updown_control (void)
+static HWND create_parent_window(void)
 {
-    HWND hWndUpDown, hWndEdit;
-    int num;
-
-    hWndEdit = create_edit_control (ES_AUTOHSCROLL | ES_NUMBER, 0);
-    hWndUpDown = create_updown_control (hWndEdit);
-    /* before we set a value, it should be '0' */
-    num = SendMessage(hWndUpDown, UDM_GETPOS, 0, 0L);
-    ok(num == 0, "Expected 0 got %d\n", num);
-    /* set a value, check it. */
-    SendMessage(hWndUpDown, UDM_SETPOS, 0L, MAKELONG( 1, 0));
-    num = SendMessage(hWndUpDown, UDM_GETPOS, 0, 0L);
-    ok(num == 1, "Expected 1 got %d\n", num);
-    /* okay, done (short set of tests!) */
-    DestroyWindow(hWndUpDown);
-    DestroyWindow(hWndEdit);
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindowEx(0, "Up-Down test parent class",
+                          "Up-Down test parent window",
+                          WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                          WS_MAXIMIZEBOX | WS_VISIBLE,
+                          0, 0, 100, 100,
+                          GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
 }
 
-START_TEST(updown)
+struct subclass_info
+{
+    WNDPROC oldproc;
+};
+
+static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, EDIT_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+    return ret;
+}
+
+static HWND create_edit_control(void)
+{
+    struct subclass_info *info;
+    RECT rect;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    GetClientRect(parent_wnd, &rect);
+    edit = CreateWindowExA(0, "EDIT", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE,
+                           0, 0, rect.right, rect.bottom,
+                           parent_wnd, NULL, GetModuleHandleA(NULL), NULL);
+    if (!edit)
+    {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
+                                            (LONG_PTR)edit_subclass_proc);
+    SetWindowLongPtrA(edit, GWLP_USERDATA, (LONG_PTR)info);
+
+    return edit;
+}
+
+static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    static long defwndproc_counter = 0;
+    LRESULT ret;
+    struct message msg;
+
+    trace("updown: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    add_message(sequences, UPDOWN_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND create_updown_control(void)
+{
+    struct subclass_info *info;
+    HWND updown;
+    RECT rect;
+
+    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
+    if (!info)
+        return NULL;
+
+    GetClientRect(parent_wnd, &rect);
+    updown = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_ALIGNRIGHT,
+                                 0, 0, rect.right, rect.bottom, parent_wnd, 1, GetModuleHandleA(NULL), edit,
+                                 100, 0, 50);
+    if (!updown)
+    {
+        HeapFree(GetProcessHeap(), 0, info);
+        return NULL;
+    }
+
+    info->oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC,
+                                            (LONG_PTR)updown_subclass_proc);
+    SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)info);
+
+    return updown;
+}
+
+static void test_updown_pos(void)
+{
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Set Range from 0 to 100 */
+    SendMessage(updown, UDM_SETRANGE, 0 , MAKELONG(100,0) );
+    r = SendMessage(updown, UDM_GETRANGE, 0,0);
+    expect(100,LOWORD(r));
+    expect(0,HIWORD(r));
+
+    /* Set the position to 5, return is not checked as it was set before func call */
+    SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(5,0) );
+    /* Since UDM_SETBUDDYINT was not set at creation HIWORD(r) will always be 1 as a return from UDM_GETPOS */
+    /* Get the position, which should be 5 */
+    r = SendMessage(updown, UDM_GETPOS, 0 , 0 );
+    expect(5,LOWORD(r));
+    expect(1,HIWORD(r));
+
+    /* Set the position to 0, return should be 5 */
+    r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(0,0) );
+    expect(5,r);
+    /* Get the position, which should be 0 */
+    r = SendMessage(updown, UDM_GETPOS, 0 , 0 );
+    expect(0,LOWORD(r));
+    expect(1,HIWORD(r));
+
+    /* Set the position to -1, return should be 0 */
+    r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(-1,0) );
+    expect(0,r);
+    /* Get the position, which should be 0 */
+    r = SendMessage(updown, UDM_GETPOS, 0 , 0 );
+    expect(0,LOWORD(r));
+    expect(1,HIWORD(r));
+
+    /* Set the position to 100, return should be 0 */
+    r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(100,0) );
+    expect(0,r);
+    /* Get the position, which should be 100 */
+    r = SendMessage(updown, UDM_GETPOS, 0 , 0 );
+    expect(100,LOWORD(r));
+    expect(1,HIWORD(r));
+
+    /* Set the position to 101, return should be 100 */
+    r = SendMessage(updown, UDM_SETPOS, 0 , MAKELONG(101,0) );
+    expect(100,r);
+    /* Get the position, which should be 100 */
+    r = SendMessage(updown, UDM_GETPOS, 0 , 0 );
+    expect(100,LOWORD(r));
+    expect(1,HIWORD(r));
+
+    ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE);
+}
+
+static void test_updown_pos32(void)
+{
+    int r;
+    int low, high;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Set the position to 0 to 1000 */
+    SendMessage(updown, UDM_SETRANGE32, 0 , 1000 );
+
+    r = SendMessage(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high );
+    expect(0,low);
+    expect(1000,high);
+
+    /* Set position to 500, don't check return since it is unset*/
+    SendMessage(updown, UDM_SETPOS32, 0 , 500 );
+
+    /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */
+
+    r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high );
+    expect(500,r);
+    expect(1,high);
+
+    /* Set position to 0, return should be 500 */
+    r = SendMessage(updown, UDM_SETPOS32, 0 , 0 );
+    expect(500,r);
+    r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high );
+    expect(0,r);
+    expect(1,high);
+
+    /* Set position to -1 which should become 0, return should be 0 */
+    r = SendMessage(updown, UDM_SETPOS32, 0 , -1 );
+    expect(0,r);
+    r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high );
+    expect(0,r);
+    expect(1,high);
+
+    /* Set position to 1000, return should be 0 */
+    r = SendMessage(updown, UDM_SETPOS32, 0 , 1000 );
+    expect(0,r);
+    r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high );
+    expect(1000,r);
+    expect(1,high);
+
+    /* Set position to 1001 which should become 1000, return should be 1000 */
+    r = SendMessage(updown, UDM_SETPOS32, 0 , 1001 );
+    expect(1000,r);
+    r = SendMessage(updown, UDM_GETPOS32, 0 , (LPARAM) &high );
+    expect(1000,r);
+    expect(1,high);
+
+    ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE);
+}
+
+static void test_updown_buddy(void)
+{
+    HWND buddyReturn;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 );
+    ok(buddyReturn == edit, "Expected edit handle\n");
+
+    buddyReturn = (HWND)SendMessage(updown, UDM_SETBUDDY, (WPARAM) edit, 0);
+    ok(buddyReturn == edit, "Expected edit handle\n");
+
+    buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 );
+    ok(buddyReturn == edit, "Expected edit handle\n");
+
+    ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_buddy_seq, "test updown buddy", TRUE);
+    ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "test updown buddy_edit", FALSE);
+}
+
+static void test_updown_base(void)
+{
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    SendMessage(updown, UDM_SETBASE, 10 , 0);
+    r = SendMessage(updown, UDM_GETBASE, 0 , 0);
+    expect(10,r);
+
+    /* Set base to an invalid value, should return 0 and stay at 10 */
+    r = SendMessage(updown, UDM_SETBASE, 80 , 0);
+    expect(0,r);
+    r = SendMessage(updown, UDM_GETBASE, 0 , 0);
+    expect(10,r);
+
+    /* Set base to 16 now, should get 16 as the return */
+    r = SendMessage(updown, UDM_SETBASE, 16 , 0);
+    expect(10,r);
+    r = SendMessage(updown, UDM_GETBASE, 0 , 0);
+    expect(16,r);
+
+    /* Set base to an invalid value, should return 0 and stay at 16 */
+    r = SendMessage(updown, UDM_SETBASE, 80 , 0);
+    expect(0,r);
+    r = SendMessage(updown, UDM_GETBASE, 0 , 0);
+    expect(16,r);
+
+    /* Set base back to 10, return should be 16 */
+    r = SendMessage(updown, UDM_SETBASE, 10 , 0);
+    expect(16,r);
+    r = SendMessage(updown, UDM_GETBASE, 0 , 0);
+    expect(10,r);
+
+    ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE);
+}
+
+static void test_updown_unicode(void)
 {
-    desktopDC=GetDC(NULL);
-    hinst = GetModuleHandleA(NULL);
+    int r;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    /* Set it to ANSI, don't check return as we don't know previous state */
+    SendMessage(updown, UDM_SETUNICODEFORMAT, 0 , 0);
+    r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0);
+    expect(0,r);
+
+    /* Now set it to Unicode format */
+    r = SendMessage(updown, UDM_SETUNICODEFORMAT, 1 , 0);
+    expect(0,r);
+    r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0);
+    expect(1,r);
+
+    /* And now set it back to ANSI */
+    r = SendMessage(updown, UDM_SETUNICODEFORMAT, 0 , 0);
+    expect(1,r);
+    r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0);
+    expect(0,r);
+
+    ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE);
+}
+
 
+static void test_create_updown_control(void)
+{
+    CHAR text[MAX_PATH];
+
+    parent_wnd = create_parent_window();
+    ok(parent_wnd != NULL, "Failed to create parent window!\n");
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent window", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    edit = create_edit_control();
+    ok(edit != NULL, "Failed to create edit control\n");
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_edit_to_parent_seq, "add edit control to parent", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    updown = create_updown_control();
+    ok(updown != NULL, "Failed to create updown control\n");
+    ok_sequence(sequences, PARENT_SEQ_INDEX, add_updown_to_parent_seq, "add updown control to parent", TRUE);
+    ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "add updown control with edit", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    GetWindowTextA(edit, text, MAX_PATH);
+    ok(lstrlenA(text) == 0, "Expected empty string\n");
+    ok_sequence(sequences, EDIT_SEQ_INDEX, get_edit_text_seq, "get edit text", FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    test_updown_pos();
+    test_updown_pos32();
+    test_updown_buddy();
+    test_updown_base();
+    test_updown_unicode();
+}
+
+START_TEST(updown)
+{
     InitCommonControls();
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    test_updown_control();
+    test_create_updown_control();
 }