[COMCTL32_WINETEST]
authorChristoph von Wittich <christoph_vw@reactos.org>
Sun, 30 May 2010 15:19:09 +0000 (15:19 +0000)
committerChristoph von Wittich <christoph_vw@reactos.org>
Sun, 30 May 2010 15:19:09 +0000 (15:19 +0000)
sync to wine 1.2 RC2

svn path=/trunk/; revision=47448

29 files changed:
rostests/winetests/comctl32/comboex.c
rostests/winetests/comctl32/comctl32.rbuild
rostests/winetests/comctl32/comctl32_ros.diff [deleted file]
rostests/winetests/comctl32/datetime.c
rostests/winetests/comctl32/dpa.c
rostests/winetests/comctl32/header.c
rostests/winetests/comctl32/imagelist.c
rostests/winetests/comctl32/ipaddress.c
rostests/winetests/comctl32/listview.c
rostests/winetests/comctl32/misc.c
rostests/winetests/comctl32/monthcal.c
rostests/winetests/comctl32/mru.c
rostests/winetests/comctl32/msg.c [deleted file]
rostests/winetests/comctl32/msg.h
rostests/winetests/comctl32/progress.c
rostests/winetests/comctl32/propsheet.c
rostests/winetests/comctl32/rebar.c
rostests/winetests/comctl32/resources.h
rostests/winetests/comctl32/rsrc.rc
rostests/winetests/comctl32/status.c
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
rostests/winetests/comctl32/treeview.c
rostests/winetests/comctl32/updown.c
rostests/winetests/comctl32/v6util.h [new file with mode: 0644]

index 1e74192..f9a42df 100644 (file)
 #include <commctrl.h>
 
 #include "wine/test.h"
 #include <commctrl.h>
 
 #include "wine/test.h"
+#include "msg.h"
+
+#define EDITBOX_SEQ_INDEX  0
+#define NUM_MSG_SEQUENCES  1
+
+#define EDITBOX_ID         0
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
 static HWND hComboExParentWnd;
 static HINSTANCE hMainHinst;
 static const char ComboExTestClass[] = "ComboExTestClass";
 
 
 static HWND hComboExParentWnd;
 static HINSTANCE hMainHinst;
 static const char ComboExTestClass[] = "ComboExTestClass";
 
+static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+
 #define MAX_CHARS 100
 static char *textBuffer = NULL;
 
 #define MAX_CHARS 100
 static char *textBuffer = NULL;
 
@@ -42,7 +54,7 @@ static LONG addItem(HWND cbex, int idx, LPTSTR text) {
     cbexItem.iItem = idx;
     cbexItem.pszText    = text;
     cbexItem.cchTextMax = 0;
     cbexItem.iItem = idx;
     cbexItem.pszText    = text;
     cbexItem.cchTextMax = 0;
-    return (LONG)SendMessage(cbex, CBEM_INSERTITEM, 0,(LPARAM)&cbexItem);
+    return SendMessage(cbex, CBEM_INSERTITEM, 0, (LPARAM)&cbexItem);
 }
 
 static LONG setItem(HWND cbex, int idx, LPTSTR text) {
 }
 
 static LONG setItem(HWND cbex, int idx, LPTSTR text) {
@@ -52,11 +64,11 @@ static LONG setItem(HWND cbex, int idx, LPTSTR text) {
     cbexItem.iItem = idx;
     cbexItem.pszText    = text;
     cbexItem.cchTextMax = 0;
     cbexItem.iItem = idx;
     cbexItem.pszText    = text;
     cbexItem.cchTextMax = 0;
-    return (LONG)SendMessage(cbex, CBEM_SETITEM, 0,(LPARAM)&cbexItem);
+    return SendMessage(cbex, CBEM_SETITEM, 0, (LPARAM)&cbexItem);
 }
 
 static LONG delItem(HWND cbex, int idx) {
 }
 
 static LONG delItem(HWND cbex, int idx) {
-    return (LONG)SendMessage(cbex, CBEM_DELETEITEM, (LPARAM)idx, 0);
+    return SendMessage(cbex, CBEM_DELETEITEM, idx, 0);
 }
 
 static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEM *cbItem) {
 }
 
 static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEM *cbItem) {
@@ -65,7 +77,51 @@ static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEM *cbItem) {
     cbItem->pszText      = textBuffer;
     cbItem->iItem        = idx;
     cbItem->cchTextMax   = 100;
     cbItem->pszText      = textBuffer;
     cbItem->iItem        = idx;
     cbItem->cchTextMax   = 100;
-    return (LONG)SendMessage(cbex, CBEM_GETITEM, 0, (LPARAM)cbItem);
+    return SendMessage(cbex, CBEM_GETITEM, 0, (LPARAM)cbItem);
+}
+
+static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    WNDPROC oldproc = (WNDPROC)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;
+    msg.id     = EDITBOX_ID;
+
+    if (message != WM_PAINT &&
+        message != WM_ERASEBKGND &&
+        message != WM_NCPAINT &&
+        message != WM_NCHITTEST &&
+        message != WM_GETTEXT &&
+        message != WM_GETICON &&
+        message != WM_DEVICECHANGE)
+    {
+        add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+    return ret;
+}
+
+static HWND subclass_editbox(HWND hwndComboEx)
+{
+    WNDPROC oldproc;
+    HWND hwnd;
+
+    hwnd = (HWND)SendMessage(hwndComboEx, CBEM_GETEDITCONTROL, 0, 0);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                         (LONG_PTR)editbox_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
+
+    return hwnd;
 }
 
 static void test_comboboxex(void) {
 }
 
 static void test_comboboxex(void) {
@@ -288,6 +344,41 @@ static void test_WM_LBUTTONDOWN(void)
     DestroyWindow(hComboEx);
 }
 
     DestroyWindow(hComboEx);
 }
 
+static void test_CB_GETLBTEXT(void)
+{
+    HWND hCombo;
+    CHAR buff[1];
+    COMBOBOXEXITEMA item;
+    LRESULT ret;
+
+    hCombo = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+    /* set text to null */
+    addItem(hCombo, 0, NULL);
+
+    buff[0] = 'a';
+    item.mask = CBEIF_TEXT;
+    item.iItem = 0;
+    item.pszText = buff;
+    item.cchTextMax = 1;
+    ret = SendMessage(hCombo, CBEM_GETITEMA, 0, (LPARAM)&item);
+    ok(ret != 0, "CBEM_GETITEM failed\n");
+    ok(buff[0] == 0, "\n");
+
+    ret = SendMessage(hCombo, CB_GETLBTEXTLEN, 0, 0);
+    ok(ret == 0, "Expected zero length\n");
+
+    ret = SendMessage(hCombo, CB_GETLBTEXTLEN, 0, 0);
+    ok(ret == 0, "Expected zero length\n");
+
+    buff[0] = 'a';
+    ret = SendMessage(hCombo, CB_GETLBTEXT, 0, (LPARAM)buff);
+    ok(ret == 0, "Expected zero length\n");
+    ok(buff[0] == 0, "Expected null terminator as a string, got %s\n", buff);
+
+    DestroyWindow(hCombo);
+}
+
 static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     switch(msg) {
 static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     switch(msg) {
@@ -321,6 +412,8 @@ static int init(void)
     iccex.dwICC  = ICC_USEREX_CLASSES;
     pInitCommonControlsEx(&iccex);
 
     iccex.dwICC  = ICC_USEREX_CLASSES;
     pInitCommonControlsEx(&iccex);
 
+    pSetWindowSubclass = (void*)GetProcAddress(hComctl32, (LPSTR)410);
+
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
     wc.style = CS_HREDRAW | CS_VREDRAW;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
@@ -355,13 +448,87 @@ static void cleanup(void)
     UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
 }
 
     UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
 }
 
+static void test_comboboxex_subclass(void)
+{
+    HWND hComboEx, hCombo, hEdit;
+
+    hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+    hCombo = (HWND)SendMessage(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0);
+    ok(hCombo != NULL, "Failed to get internal combo\n");
+    hEdit = (HWND)SendMessage(hComboEx, CBEM_GETEDITCONTROL, 0, 0);
+    ok(hEdit != NULL, "Failed to get internal edit\n");
+
+    if (pSetWindowSubclass)
+    {
+        ok(GetPropA(hCombo, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+        ok(GetPropA(hEdit, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+    }
+
+    DestroyWindow(hComboEx);
+}
+
+static const struct message test_setitem_edit_seq[] = {
+    { WM_SETTEXT, sent|id, 0, 0, EDITBOX_ID },
+    { EM_SETSEL, sent|id|wparam|lparam, 0,  0, EDITBOX_ID },
+    { EM_SETSEL, sent|id|wparam|lparam, 0, -1, EDITBOX_ID },
+    { 0 }
+};
+
+static void test_get_set_item(void)
+{
+    char textA[] = "test";
+    HWND hComboEx;
+    COMBOBOXEXITEMA item;
+    BOOL ret;
+
+    hComboEx = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+    subclass_editbox(hComboEx);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.mask = CBEIF_TEXT;
+    item.pszText = textA;
+    item.iItem = -1;
+    ret = SendMessage(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+
+    ok_sequence(sequences, EDITBOX_SEQ_INDEX, test_setitem_edit_seq, "set item data for edit", FALSE);
+
+    /* get/set lParam */
+    item.mask = CBEIF_LPARAM;
+    item.iItem = -1;
+    item.lParam = 0xdeadbeef;
+    ret = SendMessage(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok(item.lParam == 0, "Expected zero, got %ld\n", item.lParam);
+
+    item.lParam = 0xdeadbeef;
+    ret = SendMessage(hComboEx, CBEM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+
+    item.lParam = 0;
+    ret = SendMessage(hComboEx, CBEM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok(item.lParam == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", item.lParam);
+
+    DestroyWindow(hComboEx);
+}
+
 START_TEST(comboex)
 {
     if (!init())
         return;
 
 START_TEST(comboex)
 {
     if (!init())
         return;
 
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
     test_comboboxex();
     test_WM_LBUTTONDOWN();
     test_comboboxex();
     test_WM_LBUTTONDOWN();
+    test_CB_GETLBTEXT();
+    test_comboboxex_subclass();
+    test_get_set_item();
 
     cleanup();
 }
 
     cleanup();
 }
index 9480462..d1e44b5 100644 (file)
@@ -4,6 +4,8 @@
 <module name="comctl32_winetest" type="win32cui" installbase="bin" installname="comctl32_winetest.exe" allowwarnings="true">
        <include base="comctl32_winetest">.</include>
        <define name="__ROS_LONG64__" />
 <module name="comctl32_winetest" type="win32cui" installbase="bin" installname="comctl32_winetest.exe" allowwarnings="true">
        <include base="comctl32_winetest">.</include>
        <define name="__ROS_LONG64__" />
+       <redefine name="_WIN32_WINNT">0x0600</redefine>
+       <redefine name="_WIN32_IE">0x0500</redefine>
        <file>comboex.c</file>
        <file>datetime.c</file>
        <file>dpa.c</file>
        <file>comboex.c</file>
        <file>datetime.c</file>
        <file>dpa.c</file>
@@ -14,7 +16,6 @@
        <file>misc.c</file>
        <file>monthcal.c</file>
        <file>mru.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>progress.c</file>
        <file>propsheet.c</file>
        <file>rebar.c</file>
diff --git a/rostests/winetests/comctl32/comctl32_ros.diff b/rostests/winetests/comctl32/comctl32_ros.diff
deleted file mode 100644 (file)
index d8b962d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-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"
-Index: mru.c
-===================================================================
---- mru.c      (revision 25766)
-+++ mru.c      (working copy)
-@@ -75,7 +75,7 @@
- /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
--static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
-+static LONG mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
- {
-     LONG ret;
-     DWORD dwMaxSubkeyLen, dwMaxValueLen;
index 8fdbbe5..a97ab34 100644 (file)
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
 static const struct message test_dtm_set_format_seq[] = {
 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 },
+    { DTM_SETFORMATA, sent|wparam|lparam, 00 },
+    { DTM_SETFORMATA, sent|wparam, 0 },
     { 0 }
 };
 
 static const struct message test_dtm_set_and_get_mccolor_seq[] = {
     { 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 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(255, 255, 255) },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, RGB(100, 180, 220) },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_BACKGROUND, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(255, 255, 255) },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, RGB(100, 180, 220) },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_MONTHBK, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(255, 255, 255) },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, RGB(100, 180, 220) },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TEXT, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(255, 255, 255) },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, RGB(100, 180, 220) },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLEBK, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(255, 255, 255) },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, RGB(100, 180, 220) },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TITLETEXT, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(255, 255, 255) },
+    { DTM_SETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, RGB(100, 180, 220) },
+    { DTM_GETMCCOLOR, sent|wparam|lparam, MCSC_TRAILINGTEXT, 0 },
     { 0 }
 };
 
 static const struct message test_dtm_set_and_get_mcfont_seq[] = {
     { 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 },
+    { DTM_SETMCFONT, sent|lparam, 0, 1 },
+    { DTM_GETMCFONT, sent|wparam|lparam, 00 },
     { 0 }
 };
 
 static const struct message test_dtm_get_monthcal_seq[] = {
     { 0 }
 };
 
 static const struct message test_dtm_get_monthcal_seq[] = {
-    { DTM_GETMONTHCAL, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { DTM_GETMONTHCAL, sent|wparam|lparam, 00 },
     { 0 }
 };
 
 static const struct message test_dtm_set_and_get_range_seq[] = {
     { 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 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MAX },
+    { DTM_SETRANGE, sent|wparam, GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
     { 0 }
 };
 
 static const struct message test_dtm_set_range_swap_min_max_seq[] = {
     { 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 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
+    { DTM_SETRANGE, sent|wparam, GDTR_MIN | GDTR_MAX },
+    { DTM_GETRANGE, sent|wparam, 0 },
     { 0 }
 };
 
 static const struct message test_dtm_set_and_get_system_time_seq[] = {
     { 0 }
 };
 
 static const struct message test_dtm_set_and_get_system_time_seq[] = {
-    { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 },
-    { 0x0090, sent|optional }, /* Vista */
-    { 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 },
+    { DTM_SETSYSTEMTIME, sent|wparam, GDT_NONE },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_GETSYSTEMTIME, sent|wparam, 0 },
+    { DTM_SETSYSTEMTIME, sent|wparam, 0 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message destroy_window_seq[] = {
-    { 0x0090, sent|optional }, /* Vista */
-    { 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)
 {
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -154,21 +138,17 @@ static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
     add_message(sequences, DATETIME_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
     add_message(sequences, DATETIME_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
 
     return ret;
 }
 
     defwndproc_counter--;
 
     return ret;
 }
 
-static HWND create_datetime_control(DWORD style, DWORD exstyle)
+static HWND create_datetime_control(DWORD style)
 {
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND hWndDateTime = NULL;
 
     HWND hWndDateTime = NULL;
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
     hWndDateTime = CreateWindowEx(0,
         DATETIMEPICK_CLASS,
         NULL,
     hWndDateTime = CreateWindowEx(0,
         DATETIMEPICK_CLASS,
         NULL,
@@ -179,44 +159,47 @@ static HWND create_datetime_control(DWORD style, DWORD exstyle)
         NULL,
         NULL);
 
         NULL,
         NULL);
 
-    if (!hWndDateTime) {
-        HeapFree(GetProcessHeap(), 0, info);
-        return NULL;
-    }
+    if (!hWndDateTime) return NULL;
 
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC,
-                                            (LONG_PTR)datetime_subclass_proc);
-    SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hWndDateTime, GWLP_WNDPROC,
+                                         (LONG_PTR)datetime_subclass_proc);
+    SetWindowLongPtrA(hWndDateTime, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     return hWndDateTime;
 }
 
 
     return hWndDateTime;
 }
 
-static void test_dtm_set_format(HWND hWndDateTime)
+static void test_dtm_set_format(void)
 {
 {
+    HWND hWnd;
     CHAR txt[256];
     SYSTEMTIME systime;
     LRESULT r;
 
     CHAR txt[256];
     SYSTEMTIME systime;
     LRESULT r;
 
-    r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, 0);
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    r = SendMessage(hWnd, DTM_SETFORMAT, 0, 0);
     expect(1, r);
 
     expect(1, r);
 
-    r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0,
+    r = SendMessage(hWnd, 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);
 
                    (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);
 
-    r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0,
+    r = SendMessage(hWnd, DTM_SETFORMAT, 0,
                    (LPARAM)"'hh' hh");
     expect(1, r);
     ZeroMemory(&systime, sizeof(systime));
     systime.wYear = 2000;
     systime.wMonth = systime.wDay = 1;
                    (LPARAM)"'hh' hh");
     expect(1, r);
     ZeroMemory(&systime, sizeof(systime));
     systime.wYear = 2000;
     systime.wMonth = systime.wDay = 1;
-    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
     expect(1, r);
     expect(1, r);
-    GetWindowText(hWndDateTime, txt, 256);
-    todo_wine ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt);
-    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    GetWindowText(hWnd, txt, 256);
+    ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt);
+
+    DestroyWindow(hWnd);
 }
 
 static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
 }
 
 static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char* mccolor_name)
@@ -239,43 +222,60 @@ static void test_mccolor_types(HWND hWndDateTime, int mccolor_type, const char*
     ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r);
 }
 
     ok(r==theColor, "%s: GETMCCOLOR: Expected %d, got %ld\n", mccolor_name, theColor, r);
 }
 
-static void test_dtm_set_and_get_mccolor(HWND hWndDateTime)
+static void test_dtm_set_and_get_mccolor(void)
 {
 {
-    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");
+    HWND hWnd;
+
+    hWnd = create_datetime_control(DTS_SHOWNONE);
 
 
-    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);
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    test_mccolor_types(hWnd, MCSC_BACKGROUND, "MCSC_BACKGROUND");
+    test_mccolor_types(hWnd, MCSC_MONTHBK, "MCSC_MONTHBK");
+    test_mccolor_types(hWnd, MCSC_TEXT, "MCSC_TEXT");
+    test_mccolor_types(hWnd, MCSC_TITLEBK, "MCSC_TITLEBK");
+    test_mccolor_types(hWnd, MCSC_TITLETEXT, "MCSC_TITLETEXT");
+    test_mccolor_types(hWnd, MCSC_TRAILINGTEXT, "MCSC_TRAILINGTEXT");
+
+    ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_and_get_mccolor_seq, "test_dtm_set_and_get_mccolor", FALSE);
+
+    DestroyWindow(hWnd);
 }
 
 }
 
-static void test_dtm_set_and_get_mcfont(HWND hWndDateTime)
+static void test_dtm_set_and_get_mcfont(void)
 {
     HFONT hFontOrig, hFontNew;
 {
     HFONT hFontOrig, hFontNew;
+    HWND hWnd;
+
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     hFontOrig = GetStockObject(DEFAULT_GUI_FONT);
 
     hFontOrig = GetStockObject(DEFAULT_GUI_FONT);
-    SendMessage(hWndDateTime, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
-    hFontNew = (HFONT)SendMessage(hWndDateTime, DTM_GETMCFONT, 0, 0);
+    SendMessage(hWnd, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE);
+    hFontNew = (HFONT)SendMessage(hWnd, 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);
     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);
+    DestroyWindow(hWnd);
 }
 
 }
 
-static void test_dtm_get_monthcal(HWND hWndDateTime)
+static void test_dtm_get_monthcal(void)
 {
     LRESULT r;
 {
     LRESULT r;
+    HWND hWnd;
+
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     todo_wine {
 
     todo_wine {
-        r = SendMessage(hWndDateTime, DTM_GETMONTHCAL, 0, 0);
+        r = SendMessage(hWnd, DTM_GETMONTHCAL, 0, 0);
         ok(r == 0, "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);
         ok(r == 0, "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);
+    DestroyWindow(hWnd);
 }
 
 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
 }
 
 static void fill_systime_struct(SYSTEMTIME *st, int year, int month, int dayofweek, int day, int hour, int minute, int second, int milliseconds)
@@ -318,24 +318,29 @@ static LPARAM compare_systime(SYSTEMTIME *st1, SYSTEMTIME *st2)
 #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")
 
 #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)
+static void test_dtm_set_and_get_range(void)
 {
     LRESULT r;
     SYSTEMTIME st[2];
     SYSTEMTIME getSt[2];
 {
     LRESULT r;
     SYSTEMTIME st[2];
     SYSTEMTIME getSt[2];
+    HWND hWnd;
+
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* initialize st[0] to lowest possible value */
     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
     /* initialize st[1] to all invalid numbers */
     fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000);
 
 
     /* initialize st[0] to lowest possible value */
     fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0);
     /* initialize 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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]);
 
     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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
     expect_unsuccess(0, r);
 
     /* set st[0] to all invalid numbers */
     expect_unsuccess(0, r);
 
     /* set st[0] to all invalid numbers */
@@ -343,25 +348,25 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime)
     /* set st[1] to highest possible value */
     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
 
     /* 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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]);
 
     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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
     expect_unsuccess(0, r);
     expect_unsuccess(0, r);
-    r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
+    r = SendMessage(hWnd, 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);
 
     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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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(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]);
@@ -371,9 +376,9 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime)
     /* set st[1] to highest possible value */
     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
 
     /* 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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(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]);
@@ -383,32 +388,37 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime)
     /* set st[1] to value lower than maximum */
     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
 
     /* 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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);
     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);
+
+    DestroyWindow(hWnd);
 }
 
 /* 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 */
 }
 
 /* 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)
+static void test_dtm_set_range_swap_min_max(void)
 {
     LRESULT r;
     SYSTEMTIME st[2];
     SYSTEMTIME getSt[2];
     SYSTEMTIME origSt;
 {
     LRESULT r;
     SYSTEMTIME st[2];
     SYSTEMTIME getSt[2];
     SYSTEMTIME origSt;
+    HWND hWnd;
+
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
 
 
     fill_systime_struct(&st[0], 2007, 2, 4, 15, 2, 2, 2, 2);
 
-    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&origSt);
+    r = SendMessage(hWnd, 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);
 
     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);
 
@@ -418,28 +428,33 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime)
 
     /* since min>max, min and max values should be swapped by DTM_SETRANGE
     automatically */
 
     /* 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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 {
     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]);
+        ok(compare_systime(&st[0], &getSt[0]) == 1 ||
+           broken(compare_systime(&st[0], &getSt[1]) == 1), /* comctl32 version  <= 5.80 */
+           "ST1 != ST2\n");
+
+        ok(compare_systime(&st[1], &getSt[1]) == 1 ||
+           broken(compare_systime(&st[1], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
+           "ST1 != ST2\n");
     }
 
     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
 
     }
 
     fill_systime_struct(&st[0], 1980, 1, 3, 23, 14, 34, 37, 465);
 
-    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt[0]);
+    r = SendMessage(hWnd, 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 {
     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]);
+        ok(compare_systime_time(&origSt, &getSt[0]) == 1 ||
+           broken(compare_systime_time(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
+           "ST1.time != ST2.time\n");
     }
 
     /* set st[0] to value higher than minimum */
     }
 
     /* set st[0] to value higher than minimum */
@@ -447,18 +462,21 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime)
     /* set st[1] to value lower than maximum */
     fill_systime_struct(&st[1], 2007, 3, 2, 31, 23, 59, 59, 999);
 
     /* 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);
+    r = SendMessage(hWnd, 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*/
     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);
+    r = SendMessage(hWnd, 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 {
     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]);
+        ok(compare_systime(&st[0], &getSt[1]) == 1 ||
+           broken(compare_systime(&st[0], &getSt[0]) == 1), /* comctl32 version  <= 5.80 */
+           "ST1 != ST2\n");
+
+        ok(compare_systime(&st[1], &getSt[0]) == 1 ||
+           broken(compare_systime(&st[1], &getSt[1]) == 1), /* comctl32 version <= 5.80 */
+           "ST1 != ST2\n");
     }
 
     /* set st[0] to value higher than st[1] */
     }
 
     /* set st[0] to value higher than st[1] */
@@ -467,9 +485,9 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime)
 
     /* 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*/
 
     /* 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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]);
     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]);
@@ -479,25 +497,25 @@ static void test_dtm_set_range_swap_min_max(HWND hWndDateTime)
     /* set st[1] to highest possible value */
     fill_systime_struct(&st[1], 30827, 12, 6, 31, 23, 59, 59, 999);
 
     /* 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);
+    r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETRANGE, 0, (LPARAM)getSt);
+    r = SendMessage(hWnd, 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);
     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);
+
+    DestroyWindow(hWnd);
 }
 
 }
 
-static void test_dtm_set_and_get_system_time(HWND hWndDateTime)
+static void test_dtm_set_and_get_system_time(void)
 {
     LRESULT r;
 {
     LRESULT r;
-    SYSTEMTIME st;
-    SYSTEMTIME getSt;
-    HWND hWndDateTime_test_gdt_none;
+    SYSTEMTIME st, getSt, ref;
+    HWND hWnd, hWndDateTime_test_gdt_none;
 
 
-    hWndDateTime_test_gdt_none = create_datetime_control(0, 0);
+    hWndDateTime_test_gdt_none = create_datetime_control(0);
 
     ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none);
     if(hWndDateTime_test_gdt_none) {
 
     ok(hWndDateTime_test_gdt_none!=NULL, "Expected non NULL, got %p\n", hWndDateTime_test_gdt_none);
     if(hWndDateTime_test_gdt_none) {
@@ -513,64 +531,175 @@ static void test_dtm_set_and_get_system_time(HWND hWndDateTime)
 
     DestroyWindow(hWndDateTime_test_gdt_none);
 
 
     DestroyWindow(hWndDateTime_test_gdt_none);
 
-    r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
+    hWnd = create_datetime_control(DTS_SHOWNONE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    r = SendMessage(hWnd, 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);
 
     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);
+    r = SendMessage(hWnd, 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);
 
     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);
+    r = SendMessage(hWnd, 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);
 
     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);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
     expect(1, r);
     expect(1, r);
-    r = SendMessage(hWndDateTime, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    r = SendMessage(hWnd, 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);
 
     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);
+    r = SendMessage(hWnd, 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);
     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);
+
+    /* set to some valid value */
+    GetSystemTime(&ref);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&ref);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+
+    /* year invalid */
+    st = ref;
+    st.wYear = 0;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    todo_wine expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* month invalid */
+    st = ref;
+    st.wMonth = 13;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(0, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* day invalid */
+    st = ref;
+    st.wDay = 32;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(0, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* day of week isn't validated */
+    st = ref;
+    st.wDayOfWeek = 10;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* hour invalid */
+    st = ref;
+    st.wHour = 25;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(0, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* minute invalid */
+    st = ref;
+    st.wMinute = 60;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(0, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* sec invalid */
+    st = ref;
+    st.wSecond = 60;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(0, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+    /* msec invalid */
+    st = ref;
+    st.wMilliseconds = 1000;
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(0, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    expect_systime(&ref, &getSt);
+
+    /* day of week should be calculated automatically,
+       actual day of week for this date is 4 */
+    fill_systime_struct(&st, 2009, 10, 1, 1, 0, 0, 10, 200);
+    r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+    expect(1, r);
+    r = SendMessage(hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)&getSt);
+    expect(GDT_VALID, r);
+    /* 01.10.2009 is Thursday */
+    expect(4, (LRESULT)getSt.wDayOfWeek);
+    st.wDayOfWeek = 4;
+    expect_systime(&st, &getSt);
+
+    DestroyWindow(hWnd);
 }
 
 }
 
-static void test_datetime_control(void)
+static void test_wm_set_get_text(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");
-    }
+    static const CHAR a_str[] = "a";
+    char buff[16], time[16];
+    HWND hWnd;
+    LRESULT ret;
+
+    hWnd = create_datetime_control(0);
+
+    ret = SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)a_str);
+    ok(CB_ERR == ret ||
+       broken(0 == ret) || /* comctl32 <= 4.72 */
+       broken(1 == ret), /* comctl32 <= 4.70 */
+       "Expected CB_ERR, got %ld\n", ret);
+
+    buff[0] = 0;
+    ret = SendMessage(hWnd, WM_GETTEXT, sizeof(buff), (LPARAM)buff);
+    ok(strcmp(buff, a_str) != 0, "Expected text not to change, got %s\n", buff);
 
 
-    DestroyWindow(hWndDateTime);
-    ok_sequence(sequences, DATETIME_SEQ_INDEX, destroy_window_seq, "test_dtm_set_and_get_system_time", TRUE);
+    GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, time, sizeof(time));
+    ok(!strcmp(buff, time), "Expected %s, got %s\n", time, buff);
+
+    DestroyWindow(hWnd);
+}
+
+static void test_dts_shownone(void)
+{
+    HWND hwnd;
+    DWORD style;
+
+    /* it isn't allowed to change DTS_SHOWNONE after creation */
+    hwnd = create_datetime_control(0);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    SetWindowLong(hwnd, GWL_STYLE, style | DTS_SHOWNONE);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    ok(!(style & DTS_SHOWNONE), "Expected DTS_SHOWNONE not to be set\n");
+    DestroyWindow(hwnd);
+
+    hwnd = create_datetime_control(DTS_SHOWNONE);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    SetWindowLong(hwnd, GWL_STYLE, style & ~DTS_SHOWNONE);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    ok(style & DTS_SHOWNONE, "Expected DTS_SHOWNONE to be set\n");
+    DestroyWindow(hwnd);
 }
 
 START_TEST(datetime)
 }
 
 START_TEST(datetime)
@@ -592,5 +721,13 @@ START_TEST(datetime)
 
     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    test_datetime_control();
+    test_dtm_set_format();
+    test_dtm_set_and_get_mccolor();
+    test_dtm_set_and_get_mcfont();
+    test_dtm_get_monthcal();
+    test_dtm_set_and_get_range();
+    test_dtm_set_range_swap_min_max();
+    test_dtm_set_and_get_system_time();
+    test_wm_set_get_text();
+    test_dts_shownone();
 }
 }
index 221bcba..419c1b1 100644 (file)
 
 #include "wine/test.h"
 
 
 #include "wine/test.h"
 
-#define DPAM_NOSORT 0x1
-#define DPAM_INSERT 0x4
-#define DPAM_DELETE 0x8
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
 
 
-typedef struct _ITEMDATA
+typedef struct _STREAMDATA
 {
 {
-    INT   iPos;
-    PVOID pvData;
-} ITEMDATA, *LPITEMDATA;
-
-typedef HRESULT (CALLBACK *PFNDPASTM)(LPITEMDATA,IStream*,LPARAM);
+    DWORD dwSize;
+    DWORD dwData2;
+    DWORD dwItems;
+} STREAMDATA, *PSTREAMDATA;
 
 static HDPA    (WINAPI *pDPA_Clone)(const HDPA,const HDPA);
 static HDPA    (WINAPI *pDPA_Create)(INT);
 
 static HDPA    (WINAPI *pDPA_Clone)(const HDPA,const HDPA);
 static HDPA    (WINAPI *pDPA_Create)(INT);
@@ -55,9 +52,9 @@ static INT     (WINAPI *pDPA_GetPtr)(const HDPA,INT);
 static INT     (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID);
 static BOOL    (WINAPI *pDPA_Grow)(HDPA,INT);
 static INT     (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID);
 static INT     (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID);
 static BOOL    (WINAPI *pDPA_Grow)(HDPA,INT);
 static INT     (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID);
-static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTM,IStream*,LPARAM);
+static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTREAM,IStream*,LPVOID);
 static BOOL    (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
 static BOOL    (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
-static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTM,IStream*,LPARAM);
+static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTREAM,IStream*,LPVOID);
 static INT     (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
 static BOOL    (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID);
 static BOOL    (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM);
 static INT     (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
 static BOOL    (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID);
 static BOOL    (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM);
@@ -109,14 +106,22 @@ static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
     return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
 }
 
     return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
 }
 
+/* merge callback messages counter
+   DPAMM_MERGE     1
+   DPAMM_DELETE    2
+   DPAMM_INSERT    3  */
+static INT nMessages[4];
+
 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
 {
 static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
 {
+    nMessages[op]++;
     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
     return p1;
 }        
 
 static PVOID CALLBACK CB_MergeDeleteOddSrc(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)
 {
+    nMessages[op]++;
     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
     return ((PCHAR)p2)+1;
 }
     ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
     return ((PCHAR)p2)+1;
 }
@@ -134,30 +139,30 @@ static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
     return pItem != (PVOID)3;
 }
 
     return pItem != (PVOID)3;
 }
 
-static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
+static HRESULT CALLBACK CB_Save(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
 {
     HRESULT hRes;
 {
     HRESULT hRes;
-    
-    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+
+    ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
     hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
     hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
-    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
-    hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
-    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
+    expect(S_OK, hRes);
+    hRes = IStream_Write(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
+    expect(S_OK, hRes);
     return S_OK;
 }
 
     return S_OK;
 }
 
-static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
+static HRESULT CALLBACK CB_Load(DPASTREAMINFO *pInfo, IStream *pStm, LPVOID lp)
 {
     HRESULT hRes;
     INT iOldPos;
     
     iOldPos = pInfo->iPos;
 {
     HRESULT hRes;
     INT iOldPos;
     
     iOldPos = pInfo->iPos;
-    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
     hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
     hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
-    ok(hRes == S_OK, "hRes=0x%x\n", hRes);
+    expect(S_OK, hRes);
     ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
     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%x\n", hRes);
+    hRes = IStream_Read(pStm, &pInfo->pvItem, sizeof(PVOID), NULL);
+    expect(S_OK, hRes);
     return S_OK;
 }
 
     return S_OK;
 }
 
@@ -200,7 +205,6 @@ static void test_dpa(void)
     INT ret, i;
     PVOID p;
     DWORD dw, dw2, dw3;
     INT ret, i;
     PVOID p;
     DWORD dw, dw2, dw3;
-    HRESULT hRes;
     BOOL rc;
     
     GetSystemInfo(&si);
     BOOL rc;
     
     GetSystemInfo(&si);
@@ -209,9 +213,9 @@ static void test_dpa(void)
     dpa3 = pDPA_CreateEx(0, hHeap);
     ok(dpa3 != NULL, "\n");
     ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
     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, 
+    ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
        "ret=%d error=%d\n", ret, GetLastError());
        "ret=%d error=%d\n", ret, GetLastError());
-        
+
     dpa = pDPA_Create(0);
     ok(dpa != NULL, "\n");
 
     dpa = pDPA_Create(0);
     ok(dpa != NULL, "\n");
 
@@ -288,9 +292,9 @@ static void test_dpa(void)
         ok(j == DPA_ERR, "j=%d\n", j);
         /* ... but for a binary search it's ignored */
         j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
         ok(j == DPA_ERR, "j=%d\n", j);
         /* ... but for a binary search it's ignored */
         j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
-        todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i);
+        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 get the index of a nonexistent item */
     i = pDPA_GetPtrIndex(dpa, (PVOID)7);
     ok(i == DPA_ERR, "i=%d\n", i);
@@ -335,49 +339,6 @@ static void test_dpa(void)
         ok(j != i, "i=%d\n", i);
     }
 
         ok(j != i, "i=%d\n", i);
     }
 
-    if(pDPA_Merge)
-    {
-        /* Delete all even entries from dpa */
-        p = pDPA_DeletePtr(dpa, 1);
-        p = pDPA_DeletePtr(dpa, 2);
-        p = pDPA_DeletePtr(dpa, 3);
-        rc=CheckDPA(dpa, 0x135, &dw);
-        ok(rc, "dw=0x%x\n", dw);
-    
-        /* Delete all odd entries from dpa2 */
-        pDPA_Merge(dpa2, dpa, DPAM_DELETE, 
-                   CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef);
-        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, 
-                   CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
-        pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, 
-                   CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
-    
-        rc=CheckDPA(dpa,  0x123456, &dw);
-        ok(rc, "dw=0x%x\n",  dw);
-        rc=CheckDPA(dpa2, 0x123456, &dw2);
-        ok(rc ||
-           broken(!rc), /* win98 */
-           "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, dpa2);
-        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);
     /* Setting item with huge index should work */
     ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
     ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
@@ -386,62 +347,397 @@ static void test_dpa(void)
     pDPA_DeleteAllPtrs(dpa2);
     rc=CheckDPA(dpa2, 0, &dw2);
     ok(rc, "dw2=0x%x\n", dw2);
     pDPA_DeleteAllPtrs(dpa2);
     rc=CheckDPA(dpa2, 0, &dw2);
     ok(rc, "dw2=0x%x\n", dw2);
+
+    pDPA_Destroy(dpa);
     pDPA_Destroy(dpa2);
     pDPA_Destroy(dpa2);
+    pDPA_Destroy(dpa3);
+}
+
+static void test_DPA_Merge(void)
+{
+    HDPA dpa, dpa2, dpa3;
+    INT ret, i;
+    DWORD dw;
+    BOOL rc;
+
+    if(!pDPA_Merge)
+    {
+        win_skip("DPA_Merge() not available\n");
+        return;
+    }
+
+    dpa  = pDPA_Create(0);
+    dpa2 = pDPA_Create(0);
+    dpa3 = pDPA_Create(0);
+
+    ret = pDPA_InsertPtr(dpa, 0, (PVOID)1);
+    ok(ret == 0, "ret=%d\n", ret);
+    ret = pDPA_InsertPtr(dpa, 1, (PVOID)3);
+    ok(ret == 1, "ret=%d\n", ret);
+    ret = pDPA_InsertPtr(dpa, 2, (PVOID)5);
+    ok(ret == 2, "ret=%d\n", ret);
+
+    rc = CheckDPA(dpa, 0x135, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+
+    for (i = 0; i < 6; i++)
+    {
+        ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
+        ok(ret == i, "ret=%d\n", ret);
+        ret = pDPA_InsertPtr(dpa3, i, (PVOID)(INT_PTR)(i+1));
+        ok(ret == i, "ret=%d\n", ret);
+    }
+
+    rc = CheckDPA(dpa2, 0x654321, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+    rc = CheckDPA(dpa3, 0x123456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+
+    /* Delete all odd entries from dpa2 */
+    memset(nMessages, 0, sizeof(nMessages));
+    pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
+               CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef);
+    rc = CheckDPA(dpa2, 0x246, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+
+    expect(3, nMessages[DPAMM_MERGE]);
+    expect(3, nMessages[DPAMM_DELETE]);
+    expect(0, nMessages[DPAMM_INSERT]);
+
+    for (i = 0; i < 6; i++)
+    {
+        ret = pDPA_InsertPtr(dpa2, i, (PVOID)(INT_PTR)(6-i));
+        ok(ret == i, "ret=%d\n", ret);
+    }
+
+    /* DPAM_INTERSECT - returning source while merging */
+    memset(nMessages, 0, sizeof(nMessages));
+    pDPA_Merge(dpa2, dpa, DPAM_INTERSECT,
+               CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
+    rc = CheckDPA(dpa2, 0x135, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+
+    expect(3, nMessages[DPAMM_MERGE]);
+    expect(6, nMessages[DPAMM_DELETE]);
+    expect(0, nMessages[DPAMM_INSERT]);
+
+    /* DPAM_UNION */
+    pDPA_DeleteAllPtrs(dpa);
+    pDPA_InsertPtr(dpa, 0, (PVOID)1);
+    pDPA_InsertPtr(dpa, 1, (PVOID)3);
+    pDPA_InsertPtr(dpa, 2, (PVOID)5);
+    pDPA_DeleteAllPtrs(dpa2);
+    pDPA_InsertPtr(dpa2, 0, (PVOID)2);
+    pDPA_InsertPtr(dpa2, 1, (PVOID)4);
+    pDPA_InsertPtr(dpa2, 2, (PVOID)6);
+
+    memset(nMessages, 0, sizeof(nMessages));
+    pDPA_Merge(dpa2, dpa, DPAM_UNION,
+               CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
+    rc = CheckDPA(dpa2, 0x123456, &dw);
+    ok(rc ||
+       broken(!rc && dw == 0x23456), /* 4.7x */
+       "dw=0x%x\n", dw);
+
+    expect(0, nMessages[DPAMM_MERGE]);
+    expect(0, nMessages[DPAMM_DELETE]);
+    ok(nMessages[DPAMM_INSERT] == 3 ||
+       broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
+       "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
+
+    /* Merge dpa3 into dpa2 and dpa */
+    memset(nMessages, 0, sizeof(nMessages));
+    pDPA_Merge(dpa, dpa3, DPAM_UNION|DPAM_SORTED,
+               CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
+    expect(3, nMessages[DPAMM_MERGE]);
+    expect(0, nMessages[DPAMM_DELETE]);
+    expect(3, nMessages[DPAMM_INSERT]);
+
+
+    pDPA_DeleteAllPtrs(dpa2);
+    pDPA_InsertPtr(dpa2, 0, (PVOID)2);
+    pDPA_InsertPtr(dpa2, 1, (PVOID)4);
+    pDPA_InsertPtr(dpa2, 2, (PVOID)6);
+
+    memset(nMessages, 0, sizeof(nMessages));
+    pDPA_Merge(dpa2, dpa3, DPAM_UNION|DPAM_SORTED,
+               CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
+    expect(3, nMessages[DPAMM_MERGE]);
+    expect(0, nMessages[DPAMM_DELETE]);
+    ok(nMessages[DPAMM_INSERT] == 3 ||
+       broken(nMessages[DPAMM_INSERT] == 2), /* 4.7x */
+       "Expected 3, got %d\n", nMessages[DPAMM_INSERT]);
+
+    rc = CheckDPA(dpa,  0x123456, &dw);
+    ok(rc, "dw=0x%x\n",  dw);
+    rc = CheckDPA(dpa2, 0x123456, &dw);
+    ok(rc ||
+       broken(!rc), /* win98 */
+       "dw=0x%x\n", dw);
+    rc = CheckDPA(dpa3, 0x123456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+
+    pDPA_Destroy(dpa);
+    pDPA_Destroy(dpa2);
+    pDPA_Destroy(dpa3);
+}
+
+static void test_DPA_EnumCallback(void)
+{
+    HDPA dpa;
+    BOOL rc;
+    DWORD dw;
+    INT i, ret;
 
 
-    if(pDPA_DestroyCallback)
+    if(!pDPA_EnumCallback)
     {
     {
-        nEnum = 0;
-        pDPA_DestroyCallback(dpa3, CB_EnumFirstThree, dpa3);
-        ok(nEnum == 3, "nEnum=%d\n", nEnum);
+        win_skip("DPA_EnumCallback() not available\n");
+        return;
     }
     }
-    else pDPA_Destroy(dpa3);
+
+    dpa = pDPA_Create(0);
+
+    for (i = 0; i < 6; i++)
+    {
+        ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
+        ok(ret == i, "ret=%d\n", ret);
+    }
+
+    rc = CheckDPA(dpa, 0x123456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+
+    nEnum = 0;
+    /* test callback sets first 3 items to 7 */
+    pDPA_EnumCallback(dpa, CB_EnumFirstThree, dpa);
+    rc = CheckDPA(dpa, 0x777456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
+    ok(nEnum == 3, "nEnum=%d\n", nEnum);
+
+    pDPA_Destroy(dpa);
+}
+
+static void test_DPA_DestroyCallback(void)
+{
+    HDPA dpa;
+    INT i, ret;
+
+    if(!pDPA_DestroyCallback)
+    {
+        win_skip("DPA_DestroyCallback() not available\n");
+        return;
+    }
+
+    dpa = pDPA_Create(0);
+
+    for (i = 0; i < 3; i++)
+    {
+        ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
+        ok(ret == i, "ret=%d\n", ret);
+    }
+
+    nEnum = 0;
+    pDPA_DestroyCallback(dpa, CB_EnumFirstThree, dpa);
+    ok(nEnum == 3, "nEnum=%d\n", nEnum);
+}
+
+static void test_DPA_LoadStream(void)
+{
+    static const WCHAR szStg[] = { 'S','t','g',0 };
+    IStorage* pStg = NULL;
+    IStream* pStm = NULL;
+    LARGE_INTEGER li;
+    ULARGE_INTEGER uli;
+    DWORD dwMode;
+    HRESULT hRes;
+    STREAMDATA header;
+    ULONG written, ret;
+    HDPA dpa;
+
+    if(!pDPA_LoadStream)
+    {
+        win_skip("DPA_LoadStream() not available. Skipping stream tests.\n");
+        return;
+    }
+
+    hRes = CoInitialize(NULL);
+    if (hRes != S_OK)
+    {
+        ok(0, "hResult: %d\n", hRes);
+        return;
+    }
+
+    dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
+    hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
+    expect(S_OK, hRes);
+
+    hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
+    expect(S_OK, hRes);
+
+    /* write less than header size */
+    li.QuadPart = 0;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+
+    memset(&header, 0, sizeof(header));
+    written = 0;
+    uli.QuadPart = sizeof(header)-1;
+    hRes = IStream_SetSize(pStm, uli);
+    expect(S_OK, hRes);
+    hRes = IStream_Write(pStm, &header, sizeof(header)-1, &written);
+    expect(S_OK, hRes);
+    written -= sizeof(header)-1;
+    expect(0, written);
+
+    li.QuadPart = 0;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+
+    hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
+    expect(E_FAIL, hRes);
+
+    /* check stream position after header read failed */
+    li.QuadPart = 0;
+    uli.QuadPart = 1;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_CUR, &uli);
+    expect(S_OK, hRes);
+    ok(uli.QuadPart == 0, "Expected to position reset\n");
+
+    /* write valid header for empty DPA */
+    header.dwSize = sizeof(header);
+    header.dwData2 = 1;
+    header.dwItems = 0;
+    written = 0;
+
+    li.QuadPart = 0;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+
+    uli.QuadPart = sizeof(header);
+    hRes = IStream_SetSize(pStm, uli);
+    expect(S_OK, hRes);
+
+    hRes = IStream_Write(pStm, &header, sizeof(header), &written);
+    expect(S_OK, hRes);
+    written -= sizeof(header);
+    expect(0, written);
+
+    li.QuadPart = 0;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+
+    dpa = NULL;
+    hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, NULL);
+    expect(S_OK, hRes);
+    DPA_Destroy(dpa);
+
+    /* try with altered dwData2 field */
+    header.dwSize = sizeof(header);
+    header.dwData2 = 2;
+    header.dwItems = 0;
+
+    li.QuadPart = 0;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+    hRes = IStream_Write(pStm, &header, sizeof(header), &written);
+    expect(S_OK, hRes);
+    written -= sizeof(header);
+    expect(0, written);
+
+    li.QuadPart = 0;
+    hRes = IStream_Seek(pStm, li, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+
+    hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
+    expect(E_FAIL, hRes);
+
+    ret = IStream_Release(pStm);
+    ok(!ret, "ret=%d\n", ret);
+
+    ret = IStorage_Release(pStg);
+    ok(!ret, "ret=%d\n", ret);
+
+    CoUninitialize();
+}
+
+static void test_DPA_SaveStream(void)
+{
+    HDPA dpa;
+    static const WCHAR szStg[] = { 'S','t','g',0 };
+    IStorage* pStg = NULL;
+    IStream* pStm = NULL;
+    DWORD dwMode, dw;
+    HRESULT hRes;
+    ULONG ret;
+    INT i;
+    BOOL rc;
+    LARGE_INTEGER liZero;
 
     if(!pDPA_SaveStream)
 
     if(!pDPA_SaveStream)
-        goto skip_stream_tests;
+    {
+        win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
+        return;
+    }
 
     hRes = CoInitialize(NULL);
 
     hRes = CoInitialize(NULL);
-    if(hRes == S_OK)
+    if (hRes != S_OK)
     {
     {
-        static const WCHAR szStg[] = { 'S','t','g',0 };
-        IStorage* pStg = NULL;
-        IStream* pStm = NULL;
-        LARGE_INTEGER liZero;
-        DWORD dwMode;
-        liZero.QuadPart = 0;
-
-        dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
-        hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
-        ok(hRes == S_OK, "hRes=0x%x\n", hRes);
-
-        hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
-        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%x\n", hRes);
-        pDPA_Destroy(dpa);
-        
-        hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
-        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%x\n", hRes);
-            rc=CheckDPA(dpa, 0x123456, &dw);
-            ok(rc, "dw=0x%x\n", dw);
-        }
+        ok(0, "hResult: %d\n", hRes);
+        return;
+    }
 
 
-        ret = IStream_Release(pStm);
-        ok(!ret, "ret=%d\n", ret);
-       
-        ret = IStorage_Release(pStg);
-        ok(!ret, "ret=%d\n", ret);
+    dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
+    hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
+    expect(S_OK, hRes);
 
 
-        CoUninitialize();
+    hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
+    expect(S_OK, hRes);
+
+    dpa = pDPA_Create(0);
+
+    /* simple parameter check */
+    hRes = pDPA_SaveStream(dpa, NULL, pStm, NULL);
+    ok(hRes == E_INVALIDARG ||
+       broken(hRes == S_OK) /* XP and below */, "Wrong result, %d\n", hRes);
+if (0) {
+    /* crashes on XP */
+    hRes = pDPA_SaveStream(NULL, CB_Save, pStm, NULL);
+    expect(E_INVALIDARG, hRes);
+
+    hRes = pDPA_SaveStream(dpa, CB_Save, NULL, NULL);
+    expect(E_INVALIDARG, hRes);
+}
+
+    /* saving/loading */
+    for (i = 0; i < 6; i++)
+    {
+        ret = pDPA_InsertPtr(dpa, i, (PVOID)(INT_PTR)(i+1));
+        ok(ret == i, "ret=%d\n", ret);
     }
     }
-    else ok(0, "hResult: %d\n", hRes);
 
 
-skip_stream_tests:
+    liZero.QuadPart = 0;
+    hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+
+    hRes = pDPA_SaveStream(dpa, CB_Save, pStm, (void*)0xdeadbeef);
+    expect(S_OK, hRes);
+    pDPA_Destroy(dpa);
+
+    liZero.QuadPart = 0;
+    hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
+    expect(S_OK, hRes);
+    hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, (void*)0xdeadbeef);
+    expect(S_OK, hRes);
+    rc = CheckDPA(dpa, 0x123456, &dw);
+    ok(rc, "dw=0x%x\n", dw);
     pDPA_Destroy(dpa);
     pDPA_Destroy(dpa);
+
+    ret = IStream_Release(pStm);
+    ok(!ret, "ret=%d\n", ret);
+
+    ret = IStorage_Release(pStg);
+    ok(!ret, "ret=%d\n", ret);
+
+    CoUninitialize();
 }
 
 START_TEST(dpa)
 }
 
 START_TEST(dpa)
@@ -450,8 +746,16 @@ START_TEST(dpa)
 
     hcomctl32 = GetModuleHandleA("comctl32.dll");
 
 
     hcomctl32 = GetModuleHandleA("comctl32.dll");
 
-    if(InitFunctionPtrs(hcomctl32))
-        test_dpa();
-    else
+    if(!InitFunctionPtrs(hcomctl32))
+    {
         win_skip("Needed functions are not available\n");
         win_skip("Needed functions are not available\n");
+        return;
+    }
+
+    test_dpa();
+    test_DPA_Merge();
+    test_DPA_EnumCallback();
+    test_DPA_DestroyCallback();
+    test_DPA_LoadStream();
+    test_DPA_SaveStream();
 }
 }
index 7661253..d9b4a73 100644 (file)
@@ -24,6 +24,7 @@
 #include <assert.h>
 
 #include "wine/test.h"
 #include <assert.h>
 
 #include "wine/test.h"
+#include "v6util.h"
 #include "msg.h"
 
 typedef struct tagEXPECTEDNOTIFY
 #include "msg.h"
 
 typedef struct tagEXPECTEDNOTIFY
@@ -121,7 +122,6 @@ static const struct message deleteItem_getItemCount_seq[] = {
 };
 
 static const struct message orderArray_seq[] = {
 };
 
 static const struct message orderArray_seq[] = {
-    { HDM_GETITEMCOUNT, sent },
     { HDM_SETORDERARRAY, sent|wparam, 2 },
     { HDM_GETORDERARRAY, sent|wparam, 2 },
     { 0 }
     { HDM_SETORDERARRAY, sent|wparam, 2 },
     { HDM_GETORDERARRAY, sent|wparam, 2 },
     { 0 }
@@ -244,7 +244,7 @@ static LONG addItem(HWND hdex, int idx, LPSTR text)
     hdItem.cxy        = 100;
     hdItem.pszText    = text;
     hdItem.cchTextMax = 0;
     hdItem.cxy        = 100;
     hdItem.pszText    = text;
     hdItem.cchTextMax = 0;
-    return (LONG)SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)idx, (LPARAM)&hdItem);
+    return SendMessage(hdex, HDM_INSERTITEMA, idx, (LPARAM)&hdItem);
 }
 
 static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies)
 }
 
 static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies)
@@ -259,7 +259,7 @@ static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies)
         expect_notify(HDN_ITEMCHANGINGA, FALSE, &hdexItem);
         expect_notify(HDN_ITEMCHANGEDA, FALSE, &hdexItem);
     }
         expect_notify(HDN_ITEMCHANGINGA, FALSE, &hdexItem);
         expect_notify(HDN_ITEMCHANGEDA, FALSE, &hdexItem);
     }
-    ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem);
+    ret = SendMessage(hdex, HDM_SETITEMA, idx, (LPARAM)&hdexItem);
     if (fCheckNotifies)
         ok(notifies_received(), "setItem(): not all expected notifies were received\n");
     return ret;
     if (fCheckNotifies)
         ok(notifies_received(), "setItem(): not all expected notifies were received\n");
     return ret;
@@ -279,19 +279,19 @@ static LONG setItemUnicodeNotify(HWND hdex, int idx, LPSTR text, LPWSTR wText)
     
     expect_notify(HDN_ITEMCHANGINGW, TRUE, (HDITEMA*)&hdexNotify);
     expect_notify(HDN_ITEMCHANGEDW, TRUE, (HDITEMA*)&hdexNotify);
     
     expect_notify(HDN_ITEMCHANGINGW, TRUE, (HDITEMA*)&hdexNotify);
     expect_notify(HDN_ITEMCHANGEDW, TRUE, (HDITEMA*)&hdexNotify);
-    ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem);
+    ret = SendMessage(hdex, HDM_SETITEMA, idx, (LPARAM)&hdexItem);
     ok(notifies_received(), "setItemUnicodeNotify(): not all expected notifies were received\n");
     return ret;
 }
 
 static LONG delItem(HWND hdex, int idx)
 {
     ok(notifies_received(), "setItemUnicodeNotify(): not all expected notifies were received\n");
     return ret;
 }
 
 static LONG delItem(HWND hdex, int idx)
 {
-    return (LONG)SendMessage(hdex, HDM_DELETEITEM, (WPARAM)idx, 0);
+    return SendMessage(hdex, HDM_DELETEITEM, idx, 0);
 }
 
 static LONG getItemCount(HWND hdex)
 {
 }
 
 static LONG getItemCount(HWND hdex)
 {
-    return (LONG)SendMessage(hdex, HDM_GETITEMCOUNT, 0, 0);
+    return SendMessage(hdex, HDM_GETITEMCOUNT, 0, 0);
 }
 
 static LONG getItem(HWND hdex, int idx, LPSTR textBuffer)
 }
 
 static LONG getItem(HWND hdex, int idx, LPSTR textBuffer)
@@ -300,7 +300,7 @@ static LONG getItem(HWND hdex, int idx, LPSTR textBuffer)
     hdItem.mask         = HDI_TEXT;
     hdItem.pszText      = textBuffer;
     hdItem.cchTextMax   = MAX_CHARS;
     hdItem.mask         = HDI_TEXT;
     hdItem.pszText      = textBuffer;
     hdItem.cchTextMax   = MAX_CHARS;
-    return (LONG)SendMessage(hdex, HDM_GETITEMA, (WPARAM)idx, (LPARAM)&hdItem);
+    return SendMessage(hdex, HDM_GETITEMA, idx, (LPARAM)&hdItem);
 }
 
 static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA *phdiRead)
 }
 
 static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA *phdiRead)
@@ -396,14 +396,9 @@ static WCHAR pszUniTestW[] = {'T','S','T',0};
     ok(res == i, "Got Item Count as %d\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)
 {
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -417,7 +412,7 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara
     add_message(sequences, HEADER_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
     add_message(sequences, HEADER_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
 
     return ret;
     defwndproc_counter--;
 
     return ret;
@@ -487,7 +482,7 @@ static HWND create_custom_parent_window(void)
 
 static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
 {
 
 static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND childHandle;
     HDLAYOUT hlayout;
     RECT rectwin;
     HWND childHandle;
     HDLAYOUT hlayout;
     RECT rectwin;
@@ -505,9 +500,6 @@ static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     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,
 
     childHandle = CreateWindowEx(0, WC_HEADER, NULL,
                            WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
@@ -534,9 +526,9 @@ static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
     SetWindowPos(childHandle, winpos.hwndInsertAfter, winpos.x, winpos.y,
                  winpos.cx, winpos.cy, 0);
 
     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);
+    oldproc = (WNDPROC)SetWindowLongPtrA(childHandle, GWLP_WNDPROC,
+                                         (LONG_PTR)header_subclass_proc);
+    SetWindowLongPtrA(childHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
     return childHandle;
 }
 
     return childHandle;
 }
 
@@ -756,10 +748,10 @@ static void test_header_control (void)
         TEST_GET_ITEM(i, 4);
         TEST_GET_ITEMCOUNT(6);
     }
         TEST_GET_ITEM(i, 4);
         TEST_GET_ITEMCOUNT(6);
     }
-    
-    SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, 0);
+
+    SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, TRUE, 0);
     setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW);
     setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW);
-    SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, (LPARAM)NF_REQUERY);
+    SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, NF_REQUERY);
     setItem(hWndHeader, 3, str_items[4], TRUE);
     
     dont_expect_notify(HDN_GETDISPINFOA);
     setItem(hWndHeader, 3, str_items[4], TRUE);
     
     dont_expect_notify(HDN_GETDISPINFOA);
@@ -820,10 +812,8 @@ static void test_hdm_getitemrect(HWND hParent)
     expect(80, rect.left);
     expect(0, rect.top);
     expect(160, rect.right);
     expect(80, rect.left);
     expect(0, rect.top);
     expect(160, rect.right);
-    todo_wine
-    {
-      expect(g_customheight, rect.bottom);
-    }
+    expect(g_customheight, rect.bottom);
+
     retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect);
 
     ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal);
     retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect);
 
     ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal);
@@ -832,10 +822,8 @@ static void test_hdm_getitemrect(HWND hParent)
     expect(0, rect.top);
 
     expect(80, rect.right);
     expect(0, rect.top);
 
     expect(80, rect.right);
-    todo_wine
-    {
-      expect(g_customheight, rect.bottom);
-    }
+    expect(g_customheight, 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);
 
     retVal = SendMessage(hChild, HDM_GETITEMRECT, 10, (LPARAM) &rect);
     ok(retVal == 0, "Getting rect of nonexistent item should return 0, got %d\n", retVal);
 
@@ -907,30 +895,25 @@ static void test_hdm_hittest(HWND hParent)
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
-    todo_wine
-    {
-      expect(0, retVal);
-      expect(0, hdHitTestInfo.iItem);
-    }
+    expect(0, retVal);
+    expect(0, hdHitTestInfo.iItem);
+    expect(HHT_ONDIVIDER, hdHitTestInfo.flags);
 
     pt.x = secondItemRightBoundary - 1;
     pt.y = bottomBoundary - 1;
     hdHitTestInfo.pt = pt;
     retVal = SendMessage(hChild, HDM_HITTEST, 1, (LPARAM) &hdHitTestInfo);
 
     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, retVal);
     expect(1, hdHitTestInfo.iItem);
     expect(1, hdHitTestInfo.iItem);
+    expect(HHT_ONDIVIDER, hdHitTestInfo.flags);
 
     pt.x = secondItemRightBoundary;
     pt.y = bottomBoundary + 1;
     hdHitTestInfo.pt = pt;
 
     pt.x = secondItemRightBoundary;
     pt.y = bottomBoundary + 1;
     hdHitTestInfo.pt = pt;
-    todo_wine
-    {
-     retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
-     expect(-1, retVal);
-    }
+    retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
+    expect(-1, retVal);
+    expect(-1, hdHitTestInfo.iItem);
+    expect(HHT_BELOW, hdHitTestInfo.flags);
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, hittest_seq, "hittest sequence testing", FALSE);
 
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, hittest_seq, "hittest sequence testing", FALSE);
 
@@ -951,11 +934,9 @@ static void test_hdm_sethotdivider(HWND hParent)
                                     "adder header control to parent", FALSE);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
                                     "adder header control to parent", FALSE);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
-    todo_wine
-    {
-        retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, 0X00050005);
-        expect(0, retVal);
-    }
+    retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, MAKELPARAM(5, 5));
+    expect(0, retVal);
+
     retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 100);
     expect(100, retVal);
     retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 1);
     retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 100);
     expect(100, retVal);
     retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 1);
@@ -973,7 +954,7 @@ static void test_hdm_sethotdivider(HWND hParent)
 static void test_hdm_imageMessages(HWND hParent)
 {
     HIMAGELIST hImageList = ImageList_Create (4, 4, 0, 1, 0);
 static void test_hdm_imageMessages(HWND hParent)
 {
     HIMAGELIST hImageList = ImageList_Create (4, 4, 0, 1, 0);
-    HIMAGELIST hImageListRetVal;
+    HIMAGELIST hIml;
     HWND hChild;
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     HWND hChild;
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
@@ -983,14 +964,15 @@ static void test_hdm_imageMessages(HWND hParent)
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList);
-    ok(hImageListRetVal == NULL, "Expected NULL, got %p\n", hImageListRetVal);
+    hIml = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList);
+    ok(hIml == NULL, "Expected NULL, got %p\n", hIml);
 
 
-    hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0);
-    ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %p\n", hImageListRetVal);
+    hIml = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0);
+    ok(hIml != NULL, "Expected non-NULL handle, got %p\n", hIml);
 
 
-    hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0);
-    ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %p\n", hImageListRetVal);
+    hIml = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0);
+    ok(hIml != NULL, "Expected non-NULL handle, got %p\n", hIml);
+    ImageList_Destroy(hIml);
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE);
 
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE);
 
@@ -1025,9 +1007,16 @@ static void test_hdm_filterMessages(HWND hParent)
     todo_wine
     {
         retVal = SendMessage(hChild, HDM_CLEARFILTER, 0, 1);
     todo_wine
     {
         retVal = SendMessage(hChild, HDM_CLEARFILTER, 0, 1);
-        expect(1, retVal);
+        if (retVal == 0)
+            win_skip("HDM_CLEARFILTER needs 5.80\n");
+        else
+            expect(1, retVal);
+
         retVal = SendMessage(hChild, HDM_EDITFILTER, 1, 0);
         retVal = SendMessage(hChild, HDM_EDITFILTER, 1, 0);
-        expect(1, retVal);
+        if (retVal == 0)
+            win_skip("HDM_EDITFILTER needs 5.80\n");
+        else
+            expect(1, retVal);
     }
     if (winetest_interactive)
          ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_interactive,
     }
     if (winetest_interactive)
          ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_interactive,
@@ -1076,7 +1065,10 @@ static void test_hdm_bitmapmarginMessages(HWND hParent)
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     retVal = SendMessage(hChild, HDM_GETBITMAPMARGIN, 0, 0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     retVal = SendMessage(hChild, HDM_GETBITMAPMARGIN, 0, 0);
-    expect(6, retVal);
+    if (retVal == 0)
+        win_skip("HDM_GETBITMAPMARGIN needs 5.80\n");
+    else
+        expect(6, retVal);
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, bitmapmarginMessages_seq,
                       "bitmapmarginMessages sequence testing", FALSE);
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, bitmapmarginMessages_seq,
                       "bitmapmarginMessages sequence testing", FALSE);
@@ -1085,7 +1077,6 @@ static void test_hdm_bitmapmarginMessages(HWND hParent)
 
 static void test_hdm_index_messages(HWND hParent)
 {
 
 static void test_hdm_index_messages(HWND hParent)
 {
-
     HWND hChild;
     int retVal;
     int loopcnt;
     HWND hChild;
     int retVal;
     int loopcnt;
@@ -1098,6 +1089,7 @@ static void test_hdm_index_messages(HWND hParent)
     static char thirdHeaderItem[] = "Type";
     static char fourthHeaderItem[] = "Date Modified";
     static char *items[] = {firstHeaderItem, secondHeaderItem, thirdHeaderItem, fourthHeaderItem};
     static char thirdHeaderItem[] = "Type";
     static char fourthHeaderItem[] = "Date Modified";
     static char *items[] = {firstHeaderItem, secondHeaderItem, thirdHeaderItem, fourthHeaderItem};
+    RECT rect;
     HDITEM hdItem;
     hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
     hdItem.fmt = HDF_LEFT;
     HDITEM hdItem;
     hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
     hdItem.fmt = HDF_LEFT;
@@ -1125,17 +1117,17 @@ static void test_hdm_index_messages(HWND hParent)
 
     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_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);
+    retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0);
     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);
     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);
+    retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0);
     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);
     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);
+    retVal = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0);
     ok(retVal == 2, "Getting item count should return 2, got %d\n", retVal);
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, deleteItem_getItemCount_seq,
     ok(retVal == 2, "Getting item count should return 2, got %d\n", retVal);
 
     ok_sequence(sequences, HEADER_SEQ_INDEX, deleteItem_getItemCount_seq,
@@ -1156,9 +1148,19 @@ static void test_hdm_index_messages(HWND hParent)
     expect(0, strcmpResult);
     expect(80, hdItem.cxy);
 
     expect(0, strcmpResult);
     expect(80, hdItem.cxy);
 
+    iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, 0);
+
+    /* item should be updated just after accepting new array */
+    ShowWindow(hChild, SW_HIDE);
+    retVal = SendMessage(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray);
+    expect(TRUE, retVal);
+    rect.left = 0;
+    retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect);
+    expect(TRUE, retVal);
+    ok(rect.left != 0, "Expected updated rectangle\n");
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem);
     retVal = SendMessage(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray);
     ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal);
 
     retVal = SendMessage(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray);
     ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal);
 
@@ -1187,12 +1189,156 @@ static void test_hdm_index_messages(HWND hParent)
     DestroyWindow(hChild);
 }
 
     DestroyWindow(hChild);
 }
 
+static void test_hdf_fixedwidth(HWND hParent)
+{
+    HWND hChild;
+    HDITEM hdItem;
+    DWORD ret;
+    RECT rect;
+    HDHITTESTINFO ht;
+
+    hChild = create_custom_header_control(hParent, FALSE);
+
+    hdItem.mask = HDI_WIDTH | HDI_FORMAT;
+    hdItem.fmt = HDF_FIXEDWIDTH;
+    hdItem.cxy = 80;
+
+    ret = SendMessage(hChild, HDM_INSERTITEM, 0, (LPARAM)&hdItem);
+    expect(0, ret);
+
+    /* try to change width */
+    rect.right = rect.bottom = 0;
+    SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+    ok(rect.right  != 0, "Expected not zero width\n");
+    ok(rect.bottom != 0, "Expected not zero height\n");
+
+    SendMessage(hChild, WM_LBUTTONDOWN, 0, MAKELPARAM(rect.right, rect.bottom / 2));
+    SendMessage(hChild, WM_MOUSEMOVE, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
+    SendMessage(hChild, WM_LBUTTONUP, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
+
+    SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+
+    if (hdItem.cxy != rect.right)
+    {
+        win_skip("HDF_FIXEDWIDTH format not supported\n");
+        DestroyWindow(hChild);
+        return;
+    }
+
+    /* try to adjust with message */
+    hdItem.mask = HDI_WIDTH;
+    hdItem.cxy = 90;
+
+    ret = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM)&hdItem);
+    expect(TRUE, ret);
+
+    rect.right = 0;
+    SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(90, rect.right);
+
+    /* hittesting doesn't report ondivider flag for HDF_FIXEDWIDTH */
+    ht.pt.x = rect.right - 1;
+    ht.pt.y = rect.bottom / 2;
+    SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
+    expect(HHT_ONHEADER, ht.flags);
+
+    /* try to adjust with message */
+    hdItem.mask = HDI_FORMAT;
+    hdItem.fmt  = 0;
+
+    ret = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM)&hdItem);
+    expect(TRUE, ret);
+
+    ht.pt.x = 90;
+    ht.pt.y = rect.bottom / 2;
+    SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
+    expect(HHT_ONDIVIDER, ht.flags);
+
+    DestroyWindow(hChild);
+}
+
+static void test_hds_nosizing(HWND hParent)
+{
+    HWND hChild;
+    HDITEM hdItem;
+    DWORD ret;
+    RECT rect;
+    HDHITTESTINFO ht;
+
+    hChild = create_custom_header_control(hParent, FALSE);
+
+    memset(&hdItem, 0, sizeof(hdItem));
+    hdItem.mask = HDI_WIDTH;
+    hdItem.cxy = 80;
+
+    ret = SendMessage(hChild, HDM_INSERTITEM, 0, (LPARAM)&hdItem);
+    expect(0, ret);
+
+    /* HDS_NOSIZING only blocks hittesting */
+    ret = GetWindowLong(hChild, GWL_STYLE);
+    SetWindowLong(hChild, GWL_STYLE, ret | HDS_NOSIZING);
+
+    /* try to change width with mouse gestures */
+    rect.right = rect.bottom = 0;
+    SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+    ok(rect.right  != 0, "Expected not zero width\n");
+    ok(rect.bottom != 0, "Expected not zero height\n");
+
+    SendMessage(hChild, WM_LBUTTONDOWN, 0, MAKELPARAM(rect.right, rect.bottom / 2));
+    SendMessage(hChild, WM_MOUSEMOVE, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
+    SendMessage(hChild, WM_LBUTTONUP, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
+
+    SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+
+    if (hdItem.cxy != rect.right)
+    {
+        win_skip("HDS_NOSIZING style not supported\n");
+        DestroyWindow(hChild);
+        return;
+    }
+
+    /* this style doesn't set HDF_FIXEDWIDTH for items */
+    hdItem.mask = HDI_FORMAT;
+    ret = SendMessage(hChild, HDM_GETITEM, 0, (LPARAM)&hdItem);
+    expect(TRUE, ret);
+    ok(!(hdItem.fmt & HDF_FIXEDWIDTH), "Unexpected HDF_FIXEDWIDTH\n");
+
+    /* try to adjust with message */
+    hdItem.mask = HDI_WIDTH;
+    hdItem.cxy = 90;
+
+    ret = SendMessage(hChild, HDM_SETITEM, 0, (LPARAM)&hdItem);
+    expect(TRUE, ret);
+
+    rect.right = 0;
+    SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(90, rect.right);
+
+    /* hittesting doesn't report ondivider flags for HDS_NOSIZING */
+    ht.pt.x = rect.right - 1;
+    ht.pt.y = rect.bottom / 2;
+    SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
+    expect(HHT_ONHEADER, ht.flags);
+
+    /* try to adjust with message */
+    ret = GetWindowLong(hChild, GWL_STYLE);
+    SetWindowLong(hChild, GWL_STYLE, ret & ~HDS_NOSIZING);
+
+    ht.pt.x = 90;
+    ht.pt.y = rect.bottom / 2;
+    SendMessage(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
+    expect(HHT_ONDIVIDER, ht.flags);
+
+    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); \
 #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, \
+    ok((nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right) || \
+        broken(draw_stage != CDDS_ITEMPREPAINT), /* comctl32 < 5.80 */ \
         "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);
 
         "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);
 
@@ -1545,15 +1691,139 @@ static int init(void)
     return 1;
 }
 
     return 1;
 }
 
+/* maximum 8 items allowed */
+static void check_orderarray(HWND hwnd, DWORD start, DWORD set, DWORD expected,
+                             int todo, int line)
+{
+    int count, i;
+    INT order[8];
+    DWORD ret, array = 0;
+
+    count = SendMessage(hwnd, HDM_GETITEMCOUNT, 0, 0);
+
+    /* initial order */
+    for(i = 1; i<=count; i++)
+        order[i-1] = start>>(4*(count-i)) & 0xf;
+
+    ret = SendMessage(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order);
+    ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARAY to succeed, got %d\n", ret);
+
+    /* new order */
+    for(i = 1; i<=count; i++)
+        order[i-1] = set>>(4*(count-i)) & 0xf;
+    ret = SendMessage(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order);
+    ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARAY to succeed, got %d\n", ret);
+
+    /* check actual order */
+    ret = SendMessage(hwnd, HDM_GETORDERARRAY, count, (LPARAM)order);
+    ok_(__FILE__, line)(ret, "Expected HDM_GETORDERARAY to succeed, got %d\n", ret);
+    for(i = 1; i<=count; i++)
+        array |= order[i-1]<<(4*(count-i));
+
+    if (todo) {
+    todo_wine
+        ok_(__FILE__, line)(array == expected, "Expected %x, got %x\n", expected, array);
+    }
+    else
+        ok_(__FILE__, line)(array == expected, "Expected %x, got %x\n", expected, array);
+}
+
+static void test_hdm_orderarray(void)
+{
+    HWND hwnd;
+    INT order[5];
+    DWORD ret;
+
+    hwnd = create_header_control();
+
+    /* three items */
+    addItem(hwnd, 0, NULL);
+    addItem(hwnd, 1, NULL);
+    addItem(hwnd, 2, NULL);
+
+    ret = SendMessage(hwnd, HDM_GETORDERARRAY, 3, (LPARAM)order);
+    if (!ret)
+    {
+        win_skip("HDM_GETORDERARRAY not implemented.\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+
+    expect(0, order[0]);
+    expect(1, order[1]);
+    expect(2, order[2]);
+
+if (0)
+{
+    /* null pointer, crashes native */
+    ret = SendMessage(hwnd, HDM_SETORDERARRAY, 3, 0);
+    expect(FALSE, ret);
+}
+    /* count out of limits */
+    ret = SendMessage(hwnd, HDM_SETORDERARRAY, 5, (LPARAM)order);
+    expect(FALSE, ret);
+    /* count out of limits */
+    ret = SendMessage(hwnd, HDM_SETORDERARRAY, 2, (LPARAM)order);
+    expect(FALSE, ret);
+
+    /* try with out of range item index */
+    /* (0,1,2)->(1,0,3) => (1,0,2) */
+    check_orderarray(hwnd, 0x120, 0x103, 0x102, FALSE, __LINE__);
+    /* (1,0,2)->(3,0,1) => (0,2,1) */
+    check_orderarray(hwnd, 0x102, 0x301, 0x021, TRUE, __LINE__);
+    /* (0,2,1)->(2,3,1) => (2,0,1) */
+    check_orderarray(hwnd, 0x021, 0x231, 0x201, FALSE, __LINE__);
+
+    /* (0,1,2)->(0,2,2) => (0,1,2) */
+    check_orderarray(hwnd, 0x012, 0x022, 0x012, FALSE, __LINE__);
+
+    addItem(hwnd, 3, NULL);
+
+    /* (0,1,2,3)->(0,1,2,2) => (0,1,3,2) */
+    check_orderarray(hwnd, 0x0123, 0x0122, 0x0132, FALSE, __LINE__);
+    /* (0,1,2,3)->(0,1,3,3) => (0,1,2,3) */
+    check_orderarray(hwnd, 0x0123, 0x0133, 0x0123, FALSE, __LINE__);
+    /* (0,1,2,3)->(0,4,2,3) => (0,1,2,3) */
+    check_orderarray(hwnd, 0x0123, 0x0423, 0x0123, FALSE, __LINE__);
+    /* (0,1,2,3)->(4,0,1,2) => (0,1,3,2) */
+    check_orderarray(hwnd, 0x0123, 0x4012, 0x0132, TRUE, __LINE__);
+    /* (0,1,3,2)->(4,0,1,4) => (0,3,1,2) */
+    check_orderarray(hwnd, 0x0132, 0x4014, 0x0312, TRUE, __LINE__);
+    /* (0,1,2,3)->(4,1,0,2) => (1,0,3,2) */
+    check_orderarray(hwnd, 0x0123, 0x4102, 0x1032, TRUE, __LINE__);
+    /* (0,1,2,3)->(0,1,4,2) => (0,1,2,3) */
+    check_orderarray(hwnd, 0x0123, 0x0142, 0x0132, FALSE, __LINE__);
+    /* (0,1,2,3)->(4,4,4,4) => (0,1,2,3) */
+    check_orderarray(hwnd, 0x0123, 0x4444, 0x0123, FALSE, __LINE__);
+    /* (0,1,2,3)->(4,4,1,2) => (0,1,3,2) */
+    check_orderarray(hwnd, 0x0123, 0x4412, 0x0132, TRUE, __LINE__);
+    /* (0,1,2,3)->(4,4,4,1) => (0,2,3,1) */
+    check_orderarray(hwnd, 0x0123, 0x4441, 0x0231, TRUE, __LINE__);
+    /* (0,1,2,3)->(1,4,4,4) => (1,0,2,3) */
+    check_orderarray(hwnd, 0x0123, 0x1444, 0x1023, FALSE, __LINE__);
+    /* (0,1,2,3)->(4,2,4,1) => (0,2,3,1) */
+    check_orderarray(hwnd, 0x0123, 0x4241, 0x0231, FALSE, __LINE__);
+    /* (0,1,2,3)->(4,2,0,1) => (2,0,3,1) */
+    check_orderarray(hwnd, 0x0123, 0x4201, 0x2031, TRUE, __LINE__);
+    /* (3,2,1,0)->(4,2,0,1) => (3,2,0,1) */
+    check_orderarray(hwnd, 0x3210, 0x4201, 0x3201, FALSE, __LINE__);
+
+    DestroyWindow(hwnd);
+}
+
 START_TEST(header)
 {
     HWND parent_hwnd;
 START_TEST(header)
 {
     HWND parent_hwnd;
+    ULONG_PTR ctx_cookie;
+    HANDLE hCtx;
+    HWND hwnd;
 
     if (!init())
         return;
 
     test_header_control();
     test_header_order();
 
     if (!init())
         return;
 
     test_header_control();
     test_header_order();
+    test_hdm_orderarray();
     test_customdraw();
 
     DestroyWindow(hHeaderParentWnd);
     test_customdraw();
 
     DestroyWindow(hHeaderParentWnd);
@@ -1573,6 +1843,33 @@ START_TEST(header)
     test_hdm_unicodeformatMessages(parent_hwnd);
     test_hdm_bitmapmarginMessages(parent_hwnd);
 
     test_hdm_unicodeformatMessages(parent_hwnd);
     test_hdm_bitmapmarginMessages(parent_hwnd);
 
-    DestroyWindow(parent_hwnd);
+    if (!load_v6_module(&ctx_cookie, &hCtx))
+    {
+        DestroyWindow(parent_hwnd);
+        return;
+    }
+
+    /* this is a XP SP3 failure workaround */
+    hwnd = CreateWindowExA(0, WC_HEADER, NULL,
+                           WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
+                           0, 0, 100, 100,
+                           parent_hwnd, NULL, GetModuleHandleA(NULL), NULL);
 
 
+    if (!IsWindow(hwnd))
+    {
+        win_skip("FIXME: failed to create Header window.\n");
+        unload_v6_module(ctx_cookie, hCtx);
+        DestroyWindow(parent_hwnd);
+        return;
+    }
+    else
+        DestroyWindow(hwnd);
+
+    /* comctl32 version 6 tests start here */
+    test_hdf_fixedwidth(parent_hwnd);
+    test_hds_nosizing(parent_hwnd);
+
+    unload_v6_module(ctx_cookie, hCtx);
+
+    DestroyWindow(parent_hwnd);
 }
 }
index 3fe249f..cf749c8 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright 2004 Michael Stefaniuc
  * Copyright 2002 Mike McCormack for CodeWeavers
  * Copyright 2007 Dmitry Timoshkov
  * Copyright 2004 Michael Stefaniuc
  * Copyright 2002 Mike McCormack for CodeWeavers
  * Copyright 2007 Dmitry Timoshkov
+ * Copyright 2009 Owen Rudge for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  * 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 "objbase.h"
 #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
 #include "winuser.h"
 #include "objbase.h"
 #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
+#include "initguid.h"
+#include "commoncontrols.h"
+#include "shellapi.h"
 
 #include "wine/test.h"
 
 #include "wine/test.h"
+#include "v6util.h"
 
 #undef VISIBLE
 
 
 #undef VISIBLE
 
@@ -65,10 +70,14 @@ typedef struct _ILHEAD
 } ILHEAD;
 #include "poppack.h"
 
 } ILHEAD;
 #include "poppack.h"
 
+static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
+static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
+static HRESULT (WINAPI *pImageList_CoCreateInstance)(REFCLSID,const IUnknown *,
+    REFIID,void **);
+static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **);
 
 
-static HDC desktopDC;
 static HINSTANCE hinst;
 
 /* These macros build cursor/bitmap data in 4x4 pixel blocks */
 static HINSTANCE hinst;
 
 /* These macros build cursor/bitmap data in 4x4 pixel blocks */
@@ -327,7 +336,7 @@ static BOOL DoTest1(void)
     HICON hicon3 ;
 
     /* create an imagelist to play with */
     HICON hicon3 ;
 
     /* create an imagelist to play with */
-    himl = ImageList_Create(84,84,0x10,0,3);
+    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
     ok(himl!=0,"failed to create imagelist\n");
 
     /* load the icons to add to the image list */
     ok(himl!=0,"failed to create imagelist\n");
 
     /* load the icons to add to the image list */
@@ -393,7 +402,7 @@ static BOOL DoTest2(void)
     HICON hicon3 ;
 
     /* create an imagelist to play with */
     HICON hicon3 ;
 
     /* create an imagelist to play with */
-    himl = ImageList_Create(84,84,0x10,0,3);
+    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
     ok(himl!=0,"failed to create imagelist\n");
 
     /* load the icons to add to the image list */
     ok(himl!=0,"failed to create imagelist\n");
 
     /* load the icons to add to the image list */
@@ -442,7 +451,7 @@ static BOOL DoTest3(void)
     ok(hdc!=NULL, "couldn't get DC\n");
 
     /* create an imagelist to play with */
     ok(hdc!=NULL, "couldn't get DC\n");
 
     /* create an imagelist to play with */
-    himl = ImageList_Create(48,48,0x10,0,3);
+    himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
     ok(himl!=0,"failed to create imagelist\n");
 
     /* load the icons to add to the image list */
     ok(himl!=0,"failed to create imagelist\n");
 
     /* load the icons to add to the image list */
@@ -824,7 +833,7 @@ static void check_bitmap_data(const char *bm_data, ULONG bm_data_size,
 
 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max)
 {
 
 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max)
 {
-    ILHEAD *ilh = (ILHEAD *)ilh_data;
+    const ILHEAD *ilh = (const 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->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);
@@ -981,13 +990,639 @@ static void test_imagelist_storage(void)
     iml_clear_stream_data();
 }
 
     iml_clear_stream_data();
 }
 
+static void test_shell_imagelist(void)
+{
+    BOOL (WINAPI *pSHGetImageList)(INT, REFIID, void**);
+    IImageList *iml = NULL;
+    HMODULE hShell32;
+    HRESULT hr;
+    int out = 0;
+    RECT rect;
+    int cx, cy;
+
+    /* Try to load function from shell32 */
+    hShell32 = LoadLibrary("shell32.dll");
+    pSHGetImageList = (void*)GetProcAddress(hShell32, (LPCSTR) 727);
+
+    if (!pSHGetImageList)
+    {
+        win_skip("SHGetImageList not available, skipping test\n");
+        return;
+    }
+
+    /* Get system image list */
+    hr = (pSHGetImageList)(SHIL_SYSSMALL, &IID_IImageList, (void**)&iml);
+
+    ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr);
+
+    if (hr != S_OK)
+        return;
+
+    IImageList_GetImageCount(iml, &out);
+    ok(out > 0, "IImageList_GetImageCount returned out <= 0\n");
+
+    /* Fetch the small icon size */
+    cx = GetSystemMetrics(SM_CXSMICON);
+    cy = GetSystemMetrics(SM_CYSMICON);
+
+    /* Check icon size matches */
+    IImageList_GetImageRect(iml, 0, &rect);
+    ok(((rect.right == cx) && (rect.bottom == cy)),
+                 "IImageList_GetImageRect returned r:%d,b:%d\n",
+                 rect.right, rect.bottom);
+
+    IImageList_Release(iml);
+    FreeLibrary(hShell32);
+}
+
+static HBITMAP create_test_bitmap(HDC hdc, int bpp, UINT32 pixel1, UINT32 pixel2)
+{
+    HBITMAP hBitmap;
+    UINT32 *buffer = NULL;
+    BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, bpp, BI_RGB,
+                                0, 0, 0, 0, 0}};
+
+    hBitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
+    ok(hBitmap != NULL && buffer != NULL, "CreateDIBSection failed.\n");
+
+    if(!hBitmap || !buffer)
+    {
+        DeleteObject(hBitmap);
+        return NULL;
+    }
+
+    buffer[0] = pixel1;
+    buffer[1] = pixel2;
+
+    return hBitmap;
+}
+
+static BOOL colour_match(UINT32 x, UINT32 y)
+{
+    const INT32 tolerance = 8;
+
+    const INT32 dr = abs((INT32)(x & 0x000000FF) - (INT32)(y & 0x000000FF));
+    const INT32 dg = abs((INT32)((x & 0x0000FF00) >> 8) - (INT32)((y & 0x0000FF00) >> 8));
+    const INT32 db = abs((INT32)((x & 0x00FF0000) >> 16) - (INT32)((y & 0x00FF0000) >> 16));
+
+    return (dr <= tolerance && dg <= tolerance && db <= tolerance);
+}
+
+static void check_ImageList_DrawIndirect(IMAGELISTDRAWPARAMS *ildp, UINT32 *bits,
+                                         UINT32 expected, int line)
+{
+    bits[0] = 0x00FFFFFF;
+    pImageList_DrawIndirect(ildp);
+    ok(colour_match(bits[0], expected),
+       "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
+       bits[0] & 0x00FFFFFF, expected, line);
+}
+
+
+static void check_ImageList_DrawIndirect_fStyle(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
+                                                UINT fStyle, UINT32 expected, int line)
+{
+    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
+        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, ILS_NORMAL, 0, 0x00000000};
+    check_ImageList_DrawIndirect(&ildp, bits, expected, line);
+}
+
+static void check_ImageList_DrawIndirect_ILD_ROP(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
+                                                DWORD dwRop, UINT32 expected, int line)
+{
+    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
+        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, ILD_IMAGE | ILD_ROP, dwRop, ILS_NORMAL, 0, 0x00000000};
+    check_ImageList_DrawIndirect(&ildp, bits, expected, line);
+}
+
+static void check_ImageList_DrawIndirect_fState(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, UINT fStyle,
+                                                UINT fState, DWORD Frame, UINT32 expected, int line)
+{
+    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
+        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
+    check_ImageList_DrawIndirect(&ildp, bits, expected, line);
+}
+
+static void check_ImageList_DrawIndirect_broken(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
+                                                UINT fStyle, UINT fState, DWORD Frame, UINT32 expected,
+                                                UINT32 broken_expected, int line)
+{
+    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
+        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
+    bits[0] = 0x00FFFFFF;
+    pImageList_DrawIndirect(&ildp);
+    ok(colour_match(bits[0], expected) ||
+       broken(colour_match(bits[0], broken_expected)),
+       "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
+       bits[0] & 0x00FFFFFF, expected, line);
+}
+
+static void test_ImageList_DrawIndirect(void)
+{
+    HIMAGELIST himl = NULL;
+    int ret;
+    HDC hdcDst = NULL;
+    HBITMAP hbmOld = NULL, hbmDst = NULL;
+    HBITMAP hbmMask = NULL, hbmInverseMask = NULL;
+    HBITMAP hbmImage = NULL, hbmAlphaImage = NULL, hbmTransparentImage = NULL;
+    int iImage = -1, iAlphaImage = -1, iTransparentImage = -1;
+    UINT32 *bits = 0;
+    UINT32 maskBits = 0x00000000, inverseMaskBits = 0xFFFFFFFF;
+
+    BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, 32, BI_RGB,
+                                0, 0, 0, 0, 0}};
+
+    hdcDst = CreateCompatibleDC(0);
+    ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
+    if (!hdcDst)
+        return;
+
+    hbmMask = CreateBitmap(2, 1, 1, 1, &maskBits);
+    ok(hbmMask != 0, "CreateBitmap failed\n");
+    if(!hbmMask) goto cleanup;
+
+    hbmInverseMask = CreateBitmap(2, 1, 1, 1, &inverseMaskBits);
+    ok(hbmInverseMask != 0, "CreateBitmap failed\n");
+    if(!hbmInverseMask) goto cleanup;
+
+    himl = pImageList_Create(2, 1, ILC_COLOR32, 0, 1);
+    ok(himl != 0, "ImageList_Create failed\n");
+    if(!himl) goto cleanup;
+
+    /* Add a no-alpha image */
+    hbmImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x00ABCDEF);
+    if(!hbmImage) goto cleanup;
+
+    iImage = pImageList_Add(himl, hbmImage, hbmMask);
+    ok(iImage != -1, "ImageList_Add failed\n");
+    if(iImage == -1) goto cleanup;
+
+    /* Add an alpha image */
+    hbmAlphaImage = create_test_bitmap(hdcDst, 32, 0x89ABCDEF, 0x89ABCDEF);
+    if(!hbmAlphaImage) goto cleanup;
+
+    iAlphaImage = pImageList_Add(himl, hbmAlphaImage, hbmMask);
+    ok(iAlphaImage != -1, "ImageList_Add failed\n");
+    if(iAlphaImage == -1) goto cleanup;
+
+    /* Add a transparent alpha image */
+    hbmTransparentImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x89ABCDEF);
+    if(!hbmTransparentImage) goto cleanup;
+
+    iTransparentImage = pImageList_Add(himl, hbmTransparentImage, hbmMask);
+    ok(iTransparentImage != -1, "ImageList_Add failed\n");
+    if(iTransparentImage == -1) goto cleanup;
+
+    /* 32-bit Tests */
+    bitmapInfo.bmiHeader.biBitCount = 32;
+    hbmDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok (hbmDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
+    if (!hbmDst || !bits)
+        goto cleanup;
+    hbmOld = SelectObject(hdcDst, hbmDst);
+
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_NORMAL, 0x00ABCDEF, __LINE__);
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_TRANSPARENT, 0x00ABCDEF, __LINE__);
+    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x00D4D9DD, __LINE__);
+    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, 0x00B4BDC4, __LINE__);
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_MASK, 0x00ABCDEF, __LINE__);
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_IMAGE, 0x00ABCDEF, __LINE__);
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_PRESERVEALPHA, 0x00ABCDEF, __LINE__);
+
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, 0x00D3E5F7, __LINE__);
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_TRANSPARENT, 0x00D3E5F7, __LINE__);
+    todo_wine
+    {
+        check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x009DA8B1, __LINE__);
+        check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, 0x008C99A3, __LINE__);
+
+    }
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_MASK, 0x00D3E5F7, __LINE__);
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_IMAGE, 0x00D3E5F7, __LINE__);
+    todo_wine check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_PRESERVEALPHA, 0x005D6F81, __LINE__);
+
+    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iTransparentImage, ILD_NORMAL, 0x00FFFFFF, __LINE__);
+
+    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCCOPY, 0x00ABCDEF, __LINE__);
+    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCINVERT, 0x00543210, __LINE__);
+
+    /* ILD_ROP is ignored when the image has an alpha channel */
+    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCCOPY, 0x00D3E5F7, __LINE__);
+    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCINVERT, 0x00D3E5F7, __LINE__);
+
+    todo_wine check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00CCCCCC, __LINE__);
+    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00AFAFAF, 0x00F0F0F0, __LINE__);
+
+    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_GLOW, 0, 0x00ABCDEF, __LINE__);
+    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SHADOW, 0, 0x00ABCDEF, __LINE__);
+
+    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__);
+    check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00E9F2FB, 0x00AEB7C0, __LINE__);
+    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_NORMAL, 127, 0x00E9F2FB, 0x00D3E5F7, __LINE__);
+
+cleanup:
+
+    if(hbmOld)
+        SelectObject(hdcDst, hbmOld);
+    if(hbmDst)
+        DeleteObject(hbmDst);
+
+    if(hdcDst)
+        DeleteDC(hdcDst);
+
+    if(hbmMask)
+        DeleteObject(hbmMask);
+    if(hbmInverseMask)
+        DeleteObject(hbmInverseMask);
+
+    if(hbmImage)
+        DeleteObject(hbmImage);
+    if(hbmAlphaImage)
+        DeleteObject(hbmAlphaImage);
+    if(hbmTransparentImage)
+        DeleteObject(hbmTransparentImage);
+
+    if(himl)
+    {
+        ret = ImageList_Destroy(himl);
+        ok(ret, "ImageList_Destroy failed\n");
+    }
+}
+
+static void test_iimagelist(void)
+{
+    IImageList *imgl;
+    HIMAGELIST himl;
+    HRESULT hr;
+    ULONG ret;
+
+    if (!pHIMAGELIST_QueryInterface)
+    {
+        win_skip("XP imagelist functions not available\n");
+        return;
+    }
+
+    /* test reference counting on destruction */
+    imgl = (IImageList*)createImageList(32, 32);
+    ret = IUnknown_AddRef(imgl);
+    ok(ret == 2, "Expected 2, got %d\n", ret);
+    ret = ImageList_Destroy((HIMAGELIST)imgl);
+    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+    ret = ImageList_Destroy((HIMAGELIST)imgl);
+    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+    ret = ImageList_Destroy((HIMAGELIST)imgl);
+    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
+
+    imgl = (IImageList*)createImageList(32, 32);
+    ret = IUnknown_AddRef(imgl);
+    ok(ret == 2, "Expected 2, got %d\n", ret);
+    ret = ImageList_Destroy((HIMAGELIST)imgl);
+    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
+    ret = IImageList_Release(imgl);
+    ok(ret == 0, "Expected 0, got %d\n", ret);
+    ret = ImageList_Destroy((HIMAGELIST)imgl);
+    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
+
+    if (!pImageList_CoCreateInstance)
+    {
+        win_skip("Vista imagelist functions not available\n");
+        return;
+    }
+
+    hr = pImageList_CoCreateInstance(&CLSID_ImageList, NULL, &IID_IImageList, (void **) &imgl);
+    ok(SUCCEEDED(hr), "ImageList_CoCreateInstance failed, hr=%x\n", hr);
+
+    if (hr == S_OK)
+        IImageList_Release(imgl);
+
+    himl = createImageList(32, 32);
+
+    if (!himl)
+        return;
+
+    hr = (pHIMAGELIST_QueryInterface)(himl, &IID_IImageList, (void **) &imgl);
+    ok(SUCCEEDED(hr), "HIMAGELIST_QueryInterface failed, hr=%x\n", hr);
+
+    if (hr == S_OK)
+        IImageList_Release(imgl);
+
+    ImageList_Destroy(himl);
+}
+
+static void testHotspot_v6(void)
+{
+    struct hotspot {
+        int dx;
+        int dy;
+    };
+
+#define SIZEX1 47
+#define SIZEY1 31
+#define SIZEX2 11
+#define SIZEY2 17
+#define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
+    static const struct hotspot hotspots[HOTSPOTS_MAX] = {
+        { 10, 7 },
+        { SIZEX1, SIZEY1 },
+        { -9, -8 },
+        { -7, 35 }
+    };
+    int i, j;
+    HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
+    HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
+    IImageList *imgl1, *imgl2;
+    HRESULT hr;
+
+    /* cast to IImageList */
+    imgl1 = (IImageList *) himl1;
+    imgl2 = (IImageList *) himl2;
+
+    for (i = 0; i < HOTSPOTS_MAX; i++) {
+        for (j = 0; j < HOTSPOTS_MAX; j++) {
+            int dx1 = hotspots[i].dx;
+            int dy1 = hotspots[i].dy;
+            int dx2 = hotspots[j].dx;
+            int dy2 = hotspots[j].dy;
+            int correctx, correcty, newx, newy;
+            char loc[256];
+            IImageList *imglNew;
+            POINT ppt;
+
+            hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1);
+            ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1);
+            sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
+
+            /* check merging the dragged image with a second image */
+            hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2);
+            ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
+                    dx1, dy1, dx2, dy2);
+            sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
+
+            /* check new hotspot, it should be the same like the old one */
+            hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew);
+            ok(SUCCEEDED(hr), "GetDragImage failed\n");
+            ok(ppt.x == dx1 && ppt.y == dy1,
+                    "Expected drag hotspot [%d,%d] got [%d,%d]\n",
+                    dx1, dy1, ppt.x, ppt.y);
+            /* check size of new dragged image */
+            IImageList_GetIconSize(imglNew, &newx, &newy);
+            correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
+            correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
+            ok(newx == correctx && newy == correcty,
+                    "Expected drag image size [%d,%d] got [%d,%d]\n",
+                    correctx, correcty, newx, newy);
+            sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
+            IImageList_EndDrag(imgl2);
+        }
+    }
+#undef SIZEX1
+#undef SIZEY1
+#undef SIZEX2
+#undef SIZEY2
+#undef HOTSPOTS_MAX
+    IImageList_Release(imgl2);
+    IImageList_Release(imgl1);
+}
+
+static void DoTest1_v6(void)
+{
+    IImageList *imgl;
+    HIMAGELIST himl;
+    HRESULT hr;
+
+    HICON hicon1;
+    HICON hicon2;
+    HICON hicon3;
+
+    int ret = 0;
+
+    /* create an imagelist to play with */
+    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
+    ok(himl != 0,"failed to create imagelist\n");
+
+    imgl = (IImageList *) himl;
+
+    /* load the icons to add to the image list */
+    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon1 != 0, "no hicon1\n");
+    hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon2 != 0, "no hicon2\n");
+    hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon3 != 0, "no hicon3\n");
+
+    /* remove when nothing exists */
+    hr = IImageList_Remove(imgl, 0);
+    ok(!(SUCCEEDED(hr)), "removed nonexistent icon\n");
+
+    /* removing everything from an empty imagelist should succeed */
+    hr = IImageList_Remove(imgl, -1);
+    ok(SUCCEEDED(hr), "removed nonexistent icon\n");
+
+    /* add three */
+    ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon1, &ret)) && (ret == 0),"failed to add icon1\n");
+    ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon2, &ret)) && (ret == 1),"failed to add icon2\n");
+    ok(SUCCEEDED(IImageList_ReplaceIcon(imgl, -1, hicon3, &ret)) && (ret == 2),"failed to add icon3\n");
+
+    /* remove an index out of range */
+    ok(FAILED(IImageList_Remove(imgl, 4711)),"removed nonexistent icon\n");
+
+    /* remove three */
+    ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n");
+    ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n");
+    ok(SUCCEEDED(IImageList_Remove(imgl,0)),"can't remove 0\n");
+
+    /* remove one extra */
+    ok(FAILED(IImageList_Remove(imgl, 0)),"removed nonexistent icon\n");
+
+    /* check SetImageCount/GetImageCount */
+    ok(SUCCEEDED(IImageList_SetImageCount(imgl, 3)), "couldn't increase image count\n");
+    ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 3), "invalid image count after increase\n");
+    ok(SUCCEEDED(IImageList_SetImageCount(imgl, 1)), "couldn't decrease image count\n");
+    ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 1), "invalid image count after decrease to 1\n");
+    ok(SUCCEEDED(IImageList_SetImageCount(imgl, 0)), "couldn't decrease image count\n");
+    ok(SUCCEEDED(IImageList_GetImageCount(imgl, &ret)) && (ret == 0), "invalid image count after decrease to 0\n");
+
+    /* destroy it */
+    ok(SUCCEEDED(IImageList_Release(imgl)),"release imagelist failed\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");
+}
+
+static void DoTest3_v6(void)
+{
+    IImageList *imgl;
+    HIMAGELIST himl;
+
+    HBITMAP hbm1;
+    HBITMAP hbm2;
+    HBITMAP hbm3;
+
+    IMAGELISTDRAWPARAMS imldp;
+    HWND hwndfortest;
+    HDC hdc;
+    int ret;
+
+    hwndfortest = create_a_window();
+    hdc = GetDC(hwndfortest);
+    ok(hdc!=NULL, "couldn't get DC\n");
+
+    /* create an imagelist to play with */
+    himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
+    ok(himl!=0,"failed to create imagelist\n");
+
+    imgl = (IImageList *) himl;
+
+    /* load the icons to add to the image list */
+    hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ok(hbm1 != 0, "no bitmap 1\n");
+    hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ok(hbm2 != 0, "no bitmap 2\n");
+    hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ok(hbm3 != 0, "no bitmap 3\n");
+
+    /* add three */
+    ok(SUCCEEDED(IImageList_Add(imgl, hbm1, 0, &ret)) && (ret == 0), "failed to add bitmap 1\n");
+    ok(SUCCEEDED(IImageList_Add(imgl, hbm2, 0, &ret)) && (ret == 1), "failed to add bitmap 2\n");
+
+    ok(SUCCEEDED(IImageList_SetImageCount(imgl, 3)), "Setimage count failed\n");
+    ok(SUCCEEDED(IImageList_Replace(imgl, 2, hbm3, 0)), "failed to replace bitmap 3\n");
+
+    memset(&imldp, 0, sizeof (imldp));
+    ok(FAILED(IImageList_Draw(imgl, &imldp)), "zero data succeeded!\n");
+
+    imldp.cbSize = sizeof (imldp);
+    imldp.hdcDst = hdc;
+    imldp.himl = himl;
+
+    if (FAILED(IImageList_Draw(imgl, &imldp)))
+    {
+       /* Earlier versions of native comctl32 use a smaller structure */
+       imldp.cbSize -= 3 * sizeof(DWORD);
+       ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n");
+    }
+
+    REDRAW(hwndfortest);
+    WAIT;
+
+    imldp.fStyle = SRCCOPY;
+    imldp.rgbBk = CLR_DEFAULT;
+    imldp.rgbFg = CLR_DEFAULT;
+    imldp.y = 100;
+    imldp.x = 100;
+    ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n");
+    imldp.i ++;
+    ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n");
+    imldp.i ++;
+    ok(SUCCEEDED(IImageList_Draw(imgl, &imldp)), "should succeed\n");
+    imldp.i ++;
+    ok(FAILED(IImageList_Draw(imgl, &imldp)), "should fail\n");
+
+    /* remove three */
+    ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 1st bitmap\n");
+    ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 2nd bitmap\n");
+    ok(SUCCEEDED(IImageList_Remove(imgl, 0)), "removing 3rd bitmap\n");
+
+    /* destroy it */
+    ok(SUCCEEDED(IImageList_Release(imgl)), "release imagelist failed\n");
+
+    /* bitmaps should not be deleted by the imagelist */
+    ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
+    ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
+    ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
+
+    ReleaseDC(hwndfortest, hdc);
+    DestroyWindow(hwndfortest);
+}
+
+static void testMerge_v6(void)
+{
+    HIMAGELIST himl1, himl2;
+    IImageList *imgl1, *imgl2, *merge;
+    HICON hicon1;
+    HWND hwnd = create_a_window();
+    HRESULT hr;
+    int ret;
+
+    himl1 = ImageList_Create(32,32,0,0,3);
+    ok(himl1 != NULL,"failed to create himl1\n");
+
+    himl2 = ImageList_Create(32,32,0,0,3);
+    ok(himl2 != NULL,"failed to create himl2\n");
+
+    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon1 != NULL, "failed to create hicon1\n");
+
+    if (!himl1 || !himl2 || !hicon1)
+        return;
+
+    /* cast to IImageList */
+    imgl1 = (IImageList *) himl1;
+    imgl2 = (IImageList *) himl2;
+
+    ok(SUCCEEDED(IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret)) && (ret == 0),"add icon1 to himl2 failed\n");
+
+    /* If himl1 has no images, merge still succeeds */
+    hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl1,-1 failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl1,0 failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    /* Same happens if himl2 is empty */
+    IImageList_Release(imgl2);
+    himl2 = ImageList_Create(32,32,0,0,3);
+    ok(himl2 != NULL,"failed to recreate himl2\n");
+
+    imgl2 = (IImageList *) himl2;
+
+    hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, -1, 0, 0, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl2,-1 failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl2,0 failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    /* Now try merging an image with itself */
+    ok(SUCCEEDED(IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret)) && (ret == 0),"re-add icon1 to himl2 failed\n");
+
+    hr = IImageList_Merge(imgl2, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl2 with itself failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    /* Try merging 2 different image lists */
+    ok(SUCCEEDED(IImageList_ReplaceIcon(imgl1, -1, hicon1, &ret)) && (ret == 0),"add icon1 to himl1 failed\n");
+
+    hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl1 with himl2 failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 8, 16, &IID_IImageList, (void **) &merge);
+    ok(SUCCEEDED(hr), "merge himl1 with himl2 8,16 failed\n");
+    if (SUCCEEDED(hr)) IImageList_Release(merge);
+
+    IImageList_Release(imgl1);
+    IImageList_Release(imgl2);
+
+    DestroyIcon(hicon1);
+    DestroyWindow(hwnd);
+}
+
 START_TEST(imagelist)
 {
 START_TEST(imagelist)
 {
+    ULONG_PTR ctx_cookie;
+    HANDLE hCtx;
+
     HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
     HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
+    pImageList_Create = NULL;   /* These are not needed for non-v6.0 tests*/
+    pImageList_Add = NULL;
     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
 
     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
 
-    desktopDC=GetDC(NULL);
     hinst = GetModuleHandleA(NULL);
 
     InitCommonControls();
     hinst = GetModuleHandleA(NULL);
 
     InitCommonControls();
@@ -998,4 +1633,36 @@ START_TEST(imagelist)
     DoTest3();
     testMerge();
     test_imagelist_storage();
     DoTest3();
     testMerge();
     test_imagelist_storage();
+
+    FreeLibrary(hComCtl32);
+
+    /* Now perform v6 tests */
+
+    if (!load_v6_module(&ctx_cookie, &hCtx))
+        return;
+
+    /* Reload comctl32 */
+    hComCtl32 = LoadLibraryA("comctl32.dll");
+    pImageList_Create = (void*)GetProcAddress(hComCtl32, "ImageList_Create");
+    pImageList_Add = (void*)GetProcAddress(hComCtl32, "ImageList_Add");
+    pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
+    pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
+    pImageList_CoCreateInstance = (void*)GetProcAddress(hComCtl32, "ImageList_CoCreateInstance");
+    pHIMAGELIST_QueryInterface = (void*)GetProcAddress(hComCtl32, "HIMAGELIST_QueryInterface");
+
+    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+    /* Do v6.0 tests */
+    test_ImageList_DrawIndirect();
+    test_shell_imagelist();
+    test_iimagelist();
+
+    testHotspot_v6();
+    DoTest1_v6();
+    DoTest3_v6();
+    testMerge_v6();
+
+    CoUninitialize();
+
+    unload_v6_module(ctx_cookie, hCtx);
 }
 }
index d04223c..85f92b1 100644 (file)
@@ -33,8 +33,6 @@ static HWND create_ipaddress_control (void)
     handle = CreateWindowEx(0, WC_IPADDRESS, NULL,
                            WS_BORDER|WS_VISIBLE, 0, 0, 0, 0,
                            NULL, NULL, NULL, NULL);
     handle = CreateWindowEx(0, WC_IPADDRESS, NULL,
                            WS_BORDER|WS_VISIBLE, 0, 0, 0, 0,
                            NULL, NULL, NULL, NULL);
-    assert(handle);
-
     return handle;
 }
 
     return handle;
 }
 
@@ -45,6 +43,11 @@ static void test_get_set_text(void)
     INT r;
 
     hwnd = create_ipaddress_control();
     INT r;
 
     hwnd = create_ipaddress_control();
+    if (!hwnd)
+    {
+        win_skip("IPAddress control not implemented\n");
+        return;
+    }
 
     /* check text just after creation */
     r = GetWindowText(hwnd, ip, sizeof(ip)/sizeof(CHAR));
 
     /* check text just after creation */
     r = GetWindowText(hwnd, ip, sizeof(ip)/sizeof(CHAR));
index e94bdaa..6ef82bb 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 2006 Mike McCormack for CodeWeavers
  * Copyright 2007 George Gov
  *
  * Copyright 2006 Mike McCormack for CodeWeavers
  * Copyright 2007 George Gov
+ * Copyright 2009 Nikolay Sivov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  * 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 <commctrl.h>
 
 #include "wine/test.h"
+#include "v6util.h"
 #include "msg.h"
 
 #define PARENT_SEQ_INDEX       0
 #define PARENT_FULL_SEQ_INDEX  1
 #define LISTVIEW_SEQ_INDEX     2
 #include "msg.h"
 
 #define PARENT_SEQ_INDEX       0
 #define PARENT_FULL_SEQ_INDEX  1
 #define LISTVIEW_SEQ_INDEX     2
-#define NUM_MSG_SEQUENCES      3
+#define EDITBOX_SEQ_INDEX      3
+#define COMBINED_SEQ_INDEX     4
+#define NUM_MSG_SEQUENCES      5
 
 #define LISTVIEW_ID 0
 #define HEADER_ID   1
 
 #define LISTVIEW_ID 0
 #define HEADER_ID   1
 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
        "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
 
 #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 const WCHAR testparentclassW[] =
+    {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
+
+static HWND hwndparent, hwndparentW;
+/* prevents edit box creation, LVN_BEGINLABELEDIT return value */
+static BOOL blockEdit;
+/* return nonzero on NM_HOVER */
+static BOOL g_block_hover;
+/* dumps LVN_ITEMCHANGED message data */
+static BOOL g_dump_itemchanged;
+/* format reported to control:
+   -1 falls to defproc, anything else returned */
+static INT  notifyFormat;
+/* indicates we're running < 5.80 version */
+static BOOL g_is_below_5;
+/* item data passed to LVN_GETDISPINFOA */
+static LVITEMA g_itema;
+
+static HWND subclass_editbox(HWND hwndListview);
 
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
 
 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_QUERYNEWPALETTE,   sent|optional },
-    { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
-    { WM_WINDOWPOSCHANGED,  sent|optional },
-    { WM_NCCALCSIZE,        sent|wparam|optional, 1 },
-    { 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 },
+static const struct message create_ownerdrawfixed_parent_seq[] = {
+    { WM_NOTIFYFORMAT, sent },
+    { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
+    { WM_MEASUREITEM, sent },
+    { WM_PARENTNOTIFY, sent },
     { 0 }
 };
 
     { 0 }
 };
 
@@ -71,10 +76,10 @@ 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_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_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
     { WM_NOTIFY,     sent|id|defwinproc, 0, 0, LISTVIEW_ID },
     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, LISTVIEW_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 },
+    { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
     { 0 }
 };
 
     { 0 }
 };
 
@@ -123,6 +128,8 @@ static const struct message listview_item_count_seq[] = {
     { LVM_INSERTITEM,     sent },
     { LVM_GETITEMCOUNT,   sent },
     { LVM_DELETEITEM,     sent|wparam, 2 },
     { LVM_INSERTITEM,     sent },
     { LVM_GETITEMCOUNT,   sent },
     { LVM_DELETEITEM,     sent|wparam, 2 },
+    { WM_NCPAINT,         sent|optional },
+    { WM_ERASEBKGND,      sent|optional },
     { LVM_GETITEMCOUNT,   sent },
     { LVM_DELETEALLITEMS, sent },
     { LVM_GETITEMCOUNT,   sent },
     { LVM_GETITEMCOUNT,   sent },
     { LVM_DELETEALLITEMS, sent },
     { LVM_GETITEMCOUNT,   sent },
@@ -139,6 +146,8 @@ static const struct message listview_itempos_seq[] = {
     { LVM_INSERTITEM,      sent },
     { LVM_INSERTITEM,      sent },
     { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
     { LVM_INSERTITEM,      sent },
     { LVM_INSERTITEM,      sent },
     { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
+    { WM_NCPAINT,          sent|optional },
+    { WM_ERASEBKGND,       sent|optional },
     { LVM_GETITEMPOSITION, sent|wparam,        1 },
     { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
     { LVM_GETITEMPOSITION, sent|wparam,        2 },
     { LVM_GETITEMPOSITION, sent|wparam,        1 },
     { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
     { LVM_GETITEMPOSITION, sent|wparam,        2 },
@@ -168,9 +177,128 @@ static const struct message forward_erasebkgnd_parent_seq[] = {
     { 0 }
 };
 
     { 0 }
 };
 
-struct subclass_info
-{
-    WNDPROC oldproc;
+static const struct message ownderdata_select_focus_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
+    { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
+    { 0 }
+};
+
+static const struct message ownerdata_setstate_all_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { 0 }
+};
+
+static const struct message ownerdata_defocus_all_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
+    { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { 0 }
+};
+
+static const struct message ownerdata_deselect_all_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { 0 }
+};
+
+static const struct message select_all_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
+    { 0 }
+};
+
+static const struct message textcallback_set_again_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED  },
+    { 0 }
+};
+
+static const struct message single_getdispinfo_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
+    { 0 }
+};
+
+static const struct message getitemposition_seq1[] = {
+    { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
+    { 0 }
+};
+
+static const struct message getitemposition_seq2[] = {
+    { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
+    { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
+    { 0 }
+};
+
+static const struct message editbox_create_pos[] = {
+    /* sequence sent after LVN_BEGINLABELEDIT */
+    /* next two are 4.7x specific */
+    { WM_WINDOWPOSCHANGING, sent },
+    { WM_WINDOWPOSCHANGED, sent|optional },
+
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_NCCALCSIZE, sent },
+    { WM_WINDOWPOSCHANGED, sent },
+    { WM_MOVE, sent|defwinproc },
+    { WM_SIZE, sent|defwinproc },
+    /* the rest is todo, skipped in 4.7x */
+    { WM_WINDOWPOSCHANGING, sent|optional },
+    { WM_WINDOWPOSCHANGED, sent|optional },
+    { 0 }
+};
+
+static const struct message scroll_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
+    { 0 }
+};
+
+static const struct message setredraw_seq[] = {
+    { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
+    { 0 }
+};
+
+static const struct message lvs_ex_transparentbkgnd_seq[] = {
+    { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
+    { 0 }
+};
+
+static const struct message edit_end_nochange[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
+    { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },     /* todo */
+    { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
+    { 0 }
+};
+
+static const struct message hover_parent[] = {
+    { WM_GETDLGCODE, sent }, /* todo_wine */
+    { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
+    { 0 }
+};
+
+static const struct message listview_destroy[] = {
+    { 0x0090, sent|optional }, /* Vista */
+    { WM_PARENTNOTIFY, sent },
+    { WM_SHOWWINDOW, sent },
+    { WM_WINDOWPOSCHANGING, sent },
+    { WM_WINDOWPOSCHANGED, sent|optional },
+    { WM_DESTROY, sent },
+    { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
+    { WM_NCDESTROY, sent },
+    { 0 }
 };
 
 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 };
 
 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
@@ -184,6 +312,7 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
+    if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
 
     /* log system messages, except for painting */
     if (message < WM_USER &&
 
     /* log system messages, except for painting */
     if (message < WM_USER &&
@@ -198,9 +327,67 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
 
         add_message(sequences, PARENT_SEQ_INDEX, &msg);
         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
 
         add_message(sequences, PARENT_SEQ_INDEX, &msg);
+        add_message(sequences, COMBINED_SEQ_INDEX, &msg);
     }
     add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
 
     }
     add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
 
+    switch (message)
+    {
+      case WM_NOTIFY:
+      {
+          switch (((NMHDR*)lParam)->code)
+          {
+          case LVN_BEGINLABELEDIT:
+              /* subclass edit box */
+              if (!blockEdit)
+                  subclass_editbox(((NMHDR*)lParam)->hwndFrom);
+
+              return blockEdit;
+
+          case LVN_ENDLABELEDIT:
+              {
+              /* always accept new item text */
+              NMLVDISPINFO *di = (NMLVDISPINFO*)lParam;
+              trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText);
+              return TRUE;
+              }
+          case LVN_BEGINSCROLL:
+          case LVN_ENDSCROLL:
+              {
+              NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
+
+              trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
+                                               "BEGIN" : "END", pScroll->dx, pScroll->dy);
+              }
+              break;
+          case LVN_ITEMCHANGED:
+              if (g_dump_itemchanged)
+              {
+                  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
+                  trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
+                         nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
+              }
+              break;
+          case LVN_GETDISPINFOA:
+              {
+                  NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
+                  g_itema = dispinfo->item;
+              }
+              break;
+          case NM_HOVER:
+              if (g_block_hover) return 1;
+              break;
+          }
+          break;
+      }
+      case WM_NOTIFYFORMAT:
+      {
+          /* force to return format */
+          if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
+          break;
+      }
+    }
+
     defwndproc_counter++;
     ret = DefWindowProcA(hwnd, message, wParam, lParam);
     defwndproc_counter--;
     defwndproc_counter++;
     ret = DefWindowProcA(hwnd, message, wParam, lParam);
     defwndproc_counter--;
@@ -208,39 +395,72 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
     return ret;
 }
 
     return ret;
 }
 
-static BOOL register_parent_wnd_class(void)
+static BOOL register_parent_wnd_class(BOOL Unicode)
 {
 {
-    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, 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)
+    WNDCLASSA clsA;
+    WNDCLASSW clsW;
+
+    if (Unicode)
+    {
+        clsW.style = 0;
+        clsW.lpfnWndProc = parent_wnd_proc;
+        clsW.cbClsExtra = 0;
+        clsW.cbWndExtra = 0;
+        clsW.hInstance = GetModuleHandleW(NULL);
+        clsW.hIcon = 0;
+        clsW.hCursor = LoadCursorA(0, IDC_ARROW);
+        clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
+        clsW.lpszMenuName = NULL;
+        clsW.lpszClassName = testparentclassW;
+    }
+    else
+    {
+        clsA.style = 0;
+        clsA.lpfnWndProc = parent_wnd_proc;
+        clsA.cbClsExtra = 0;
+        clsA.cbWndExtra = 0;
+        clsA.hInstance = GetModuleHandleA(NULL);
+        clsA.hIcon = 0;
+        clsA.hCursor = LoadCursorA(0, IDC_ARROW);
+        clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
+        clsA.lpszMenuName = NULL;
+        clsA.lpszClassName = "Listview test parent class";
+    }
+
+    return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
+}
+
+static HWND create_parent_window(BOOL Unicode)
 {
 {
-    if (!register_parent_wnd_class())
+    static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
+    HWND hwnd;
+
+    if (!register_parent_wnd_class(Unicode))
         return NULL;
 
         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);
+    blockEdit = FALSE;
+    notifyFormat = -1;
+
+    if (Unicode)
+        hwnd = CreateWindowExW(0, testparentclassW, nameW,
+                               WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                               WS_MAXIMIZEBOX | WS_VISIBLE,
+                               0, 0, 100, 100,
+                               GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
+    else
+        hwnd = CreateWindowExA(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);
+    SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
+    return hwnd;
 }
 
 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 }
 
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -262,76 +482,63 @@ static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
     msg.lParam = lParam;
     msg.id = LISTVIEW_ID;
     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
     msg.lParam = lParam;
     msg.id = LISTVIEW_ID;
     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
+    add_message(sequences, COMBINED_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
     return ret;
 }
 
 static HWND create_listview_control(DWORD style)
 {
     defwndproc_counter--;
     return ret;
 }
 
 static HWND create_listview_control(DWORD style)
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND hwnd;
     RECT rect;
 
     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",
     GetClientRect(hwndparent, &rect);
     hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
-                           WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style,
+                           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());
 
                            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;
-    }
+    if (!hwnd) return NULL;
 
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
-                                            (LONG_PTR)listview_subclass_proc);
-    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                        (LONG_PTR)listview_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     return hwnd;
 }
 
 
     return hwnd;
 }
 
-static HWND create_custom_listview_control(DWORD style)
+/* unicode listview window with specified parent */
+static HWND create_listview_controlW(DWORD style, HWND parent)
 {
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND hwnd;
     RECT rect;
     HWND hwnd;
     RECT rect;
+    static const WCHAR nameW[] = {'f','o','o',0};
 
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
-    GetClientRect(hwndparent, &rect);
-    hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
+    GetClientRect(parent, &rect);
+    hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
                            WS_CHILD | WS_BORDER | WS_VISIBLE | style,
                            0, 0, rect.right, rect.bottom,
                            WS_CHILD | WS_BORDER | WS_VISIBLE | style,
                            0, 0, rect.right, rect.bottom,
-                           hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+                           parent, NULL, GetModuleHandleW(NULL), NULL);
     ok(hwnd != NULL, "gle=%d\n", GetLastError());
 
     ok(hwnd != NULL, "gle=%d\n", GetLastError());
 
-    if (!hwnd)
-    {
-        HeapFree(GetProcessHeap(), 0, info);
-        return NULL;
-    }
+    if (!hwnd) return NULL;
 
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
-                                            (LONG_PTR)listview_subclass_proc);
-    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
+                                        (LONG_PTR)listview_subclass_proc);
+    SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     return hwnd;
 }
 
 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 
     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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -347,28 +554,156 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara
     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
     return ret;
 }
 
 static HWND subclass_header(HWND hwndListview)
 {
     defwndproc_counter--;
     return ret;
 }
 
 static HWND subclass_header(HWND hwndListview)
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND hwnd;
 
     HWND hwnd;
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
     hwnd = ListView_GetHeader(hwndListview);
     hwnd = ListView_GetHeader(hwndListview);
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
-                                            (LONG_PTR)header_subclass_proc);
-    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                         (LONG_PTR)header_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
+
+    return hwnd;
+}
+
+static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    WNDPROC oldproc = (WNDPROC)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;
+
+    /* all we need is sizing */
+    if (message == WM_WINDOWPOSCHANGING ||
+        message == WM_NCCALCSIZE ||
+        message == WM_WINDOWPOSCHANGED ||
+        message == WM_MOVE ||
+        message == WM_SIZE)
+    {
+        add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
+    }
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+    return ret;
+}
+
+static HWND subclass_editbox(HWND hwndListview)
+{
+    WNDPROC oldproc;
+    HWND hwnd;
+
+    hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                         (LONG_PTR)editbox_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     return hwnd;
 }
 
 
     return hwnd;
 }
 
+/* Performs a single LVM_HITTEST test */
+static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
+                              BOOL todo_item, BOOL todo_flags, int line)
+{
+    LVHITTESTINFO lpht;
+    DWORD ret;
+
+    lpht.pt.x = x;
+    lpht.pt.y = y;
+    lpht.iSubItem = 10;
+
+    trace("hittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
+    ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
+
+    if (todo_item)
+    {
+        todo_wine
+        {
+            ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
+            ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
+            ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
+        }
+    }
+    else
+    {
+        ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
+        ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
+        ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
+    }
+
+    if (todo_flags)
+    {
+        todo_wine
+            ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
+    }
+    else if (broken_flags)
+        ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
+                            "Expected flags %x, got %x\n", flags, lpht.flags);
+    else
+        ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
+}
+
+#define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
+
+/* Performs a single LVM_SUBITEMHITTEST test */
+static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
+                                     BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
+{
+    LVHITTESTINFO lpht;
+    DWORD ret;
+
+    lpht.pt.x = x;
+    lpht.pt.y = y;
+
+    trace("subhittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
+    ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
+
+    if (todo_item)
+    {
+        todo_wine
+        {
+            ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
+            ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
+        }
+    }
+    else
+    {
+        ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
+        ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
+    }
+
+    if (todo_subitem)
+    {
+        todo_wine
+            ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
+    }
+    else
+        ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
+
+    if (todo_flags)
+    {
+        todo_wine
+            ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
+    }
+    else
+        ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
+}
+
+#define test_lvm_subitemhittest(a,b,c,d,e,f,g,h,i) test_lvm_subitemhittest_(a,b,c,d,e,f,g,h,i,__LINE__)
+
 static void test_images(void)
 {
     HWND hwnd;
 static void test_images(void)
 {
     HWND hwnd;
@@ -392,7 +727,9 @@ static void test_images(void)
                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
     ok(hwnd != NULL, "failed to create listview window\n");
 
                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
     ok(hwnd != NULL, "failed to create listview window\n");
 
-    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
+    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
+                    LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
+
     ok(r == 0, "should return zero\n");
 
     r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
     ok(r == 0, "should return zero\n");
 
     r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
@@ -491,7 +828,12 @@ static void test_checkboxes(void)
     item.mask = LVIF_STATE;
     item.stateMask = 0xffff;
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
     item.mask = LVIF_STATE;
     item.stateMask = 0xffff;
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
-    ok(item.state == 0x1ccc, "state %x\n", item.state);
+    if (item.state != 0x1ccc)
+    {
+        win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
+        DestroyWindow(hwnd);
+        return;
+    }
 
     /* Now add an item without specifying a state and check that its state goes to 0x1000 */
     item.iItem = 2;
 
     /* Now add an item without specifying a state and check that its state goes to 0x1000 */
     item.iItem = 2;
@@ -827,59 +1169,99 @@ static void test_items(void)
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
     ok(r != 0, "ret %d\n", r);
 
     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
     ok(r != 0, "ret %d\n", r);
 
+    /* set text to callback value already having it */
+    r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
+    expect(TRUE, r);
+    memset (&item, 0, sizeof (item));
+    item.mask  = LVIF_TEXT;
+    item.pszText = LPSTR_TEXTCALLBACK;
+    item.iItem = 0;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
+    ok(r == 0, "ret %d\n", r);
+    memset (&item, 0, sizeof (item));
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    item.pszText = LPSTR_TEXTCALLBACK;
+    r = SendMessage(hwnd, LVM_SETITEMTEXT, 0 , (LPARAM) &item);
+    expect(TRUE, r);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
+                "check callback text comparison rule", FALSE);
+
     DestroyWindow(hwnd);
 }
 
 static void test_columns(void)
 {
     DestroyWindow(hwnd);
 }
 
 static void test_columns(void)
 {
-    HWND hwnd, hwndheader;
-    LVCOLUMN column;
-    DWORD rc;
+    HWND hwnd;
+    LVCOLUMNA column;
+    LVITEMA item;
     INT order[2];
     INT order[2];
+    CHAR buff[5];
+    DWORD rc;
 
 
-    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
+    hwnd = CreateWindowExA(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, 0xcc, sizeof(column));
     column.mask = 0;
                 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, 0xcc, sizeof(column));
     column.mask = 0;
-    rc = ListView_InsertColumn(hwnd, 0, &column);
-    ok(rc==0, "Inserting column with no mask failed with %d\n", rc);
+    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
+    ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
 
     /* Check its width */
 
     /* Check its width */
-    rc = ListView_GetColumnWidth(hwnd, 0);
-    ok(rc==10 ||
-       broken(rc==0), /* win9x */
+    rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
+    ok(rc == 10 || broken(rc == 0) /* win9x */,
        "Inserting column with no mask failed to set width to 10 with %d\n", rc);
 
     DestroyWindow(hwnd);
 
     /* LVM_GETCOLUMNORDERARRAY */
        "Inserting column with no mask failed to set width to 10 with %d\n", rc);
 
     DestroyWindow(hwnd);
 
     /* LVM_GETCOLUMNORDERARRAY */
-    hwnd = create_listview_control(0);
-    hwndheader = subclass_header(hwnd);
+    hwnd = create_listview_control(LVS_REPORT);
+    subclass_header(hwnd);
 
     memset(&column, 0, sizeof(column));
     column.mask = LVCF_WIDTH;
     column.cx = 100;
 
     memset(&column, 0, sizeof(column));
     column.mask = LVCF_WIDTH;
     column.cx = 100;
-    rc = ListView_InsertColumn(hwnd, 0, &column);
+    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
     ok(rc == 0, "Inserting column failed with %d\n", rc);
 
     column.cx = 200;
     ok(rc == 0, "Inserting column failed with %d\n", rc);
 
     column.cx = 200;
-    rc = ListView_InsertColumn(hwnd, 1, &column);
+    rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
     ok(rc == 1, "Inserting column failed with %d\n", rc);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     ok(rc == 1, "Inserting column failed with %d\n", rc);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    rc = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
-    ok(rc != 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
+    rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
+    ok(rc == 1, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
     ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
     ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
 
     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
 
     ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
     ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
 
     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
 
+    /* after column added subitem is considered as present */
+    insert_item(hwnd, 0);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    item.pszText = buff;
+    item.cchTextMax = sizeof(buff);
+    item.iItem = 0;
+    item.iSubItem = 1;
+    item.mask = LVIF_TEXT;
+    memset(&g_itema, 0, sizeof(g_itema));
+    rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    ok(rc == 1, "got %d\n", rc);
+    ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
+        "get subitem text after column added", FALSE);
+
     DestroyWindow(hwnd);
 }
     DestroyWindow(hwnd);
 }
+
 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
 static WNDPROC listviewWndProc;
 static HIMAGELIST test_create_imagelist;
 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
 static WNDPROC listviewWndProc;
 static HIMAGELIST test_create_imagelist;
@@ -907,6 +1289,8 @@ static void test_create(void)
     LVCOLUMNA col;
     RECT rect;
     WNDCLASSEX cls;
     LVCOLUMNA col;
     RECT rect;
     WNDCLASSEX cls;
+    DWORD style;
+
     cls.cbSize = sizeof(WNDCLASSEX);
     ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
     listviewWndProc = cls.lpfnWndProc;
     cls.cbSize = sizeof(WNDCLASSEX);
     ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
     listviewWndProc = cls.lpfnWndProc;
@@ -918,6 +1302,15 @@ static void test_create(void)
     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);
     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);
+
+    if (!IsWindow(hHeader))
+    {
+        /* version 4.0 */
+        win_skip("LVM_GETHEADER not implemented. Skipping.\n");
+        DestroyWindow(hList);
+        return;
+    }
+
     ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
     DestroyWindow(hList);
     ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
     DestroyWindow(hList);
@@ -937,6 +1330,8 @@ static void test_create(void)
     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
     ok(IsWindow(hHeader), "Header should be created\n");
     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
     ok(IsWindow(hHeader), "Header should be created\n");
     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
+    style = GetWindowLong(hHeader, GWL_STYLE);
+    ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
     DestroyWindow(hList);
 
     hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
     DestroyWindow(hList);
 
     hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
@@ -1033,12 +1428,14 @@ static void test_create(void)
     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
-    ok(IsWindow(hHeader), "Header should be created\n");
+    ok(IsWindow(hHeader) ||
+       broken(!IsWindow(hHeader)), /* 4.7x common controls */
+       "Header should be created\n");
     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
     DestroyWindow(hList);
 
     /* not report style accepts LVS_EX_HEADERDRAGDROP too */
     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
     DestroyWindow(hList);
 
     /* not report style accepts LVS_EX_HEADERDRAGDROP too */
-    hList = create_custom_listview_control(0);
+    hList = create_listview_control(LVS_ICON);
     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
     r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
     ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
     r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
     ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
@@ -1061,17 +1458,24 @@ static void test_create(void)
     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
 
     DestroyWindow(hList);
     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
 
     DestroyWindow(hList);
+
+    /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
+                "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
+    DestroyWindow(hList);
 }
 
 static void test_redraw(void)
 {
 }
 
 static void test_redraw(void)
 {
-    HWND hwnd, hwndheader;
+    HWND hwnd;
     HDC hdc;
     BOOL res;
     DWORD r;
 
     HDC hdc;
     BOOL res;
     DWORD r;
 
-    hwnd = create_listview_control(0);
-    hwndheader = subclass_header(hwnd);
+    hwnd = create_listview_control(LVS_REPORT);
+    subclass_header(hwnd);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -1167,7 +1571,7 @@ static void test_customdraw(void)
     HWND hwnd;
     WNDPROC oldwndproc;
 
     HWND hwnd;
     WNDPROC oldwndproc;
 
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
 
     insert_column(hwnd, 0);
     insert_column(hwnd, 1);
 
     insert_column(hwnd, 0);
     insert_column(hwnd, 1);
@@ -1193,10 +1597,10 @@ static void test_icon_spacing(void)
     WORD w, h;
     DWORD r;
 
     WORD w, h;
     DWORD r;
 
-    hwnd = create_custom_listview_control(LVS_ICON);
+    hwnd = create_listview_control(LVS_ICON);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     ok(hwnd != NULL, "failed to create a listview window\n");
 
-    r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY);
+    r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
     expect(NFR_ANSI, r);
 
     /* reset the icon spacing to defaults */
     expect(NFR_ANSI, r);
 
     /* reset the icon spacing to defaults */
@@ -1217,6 +1621,13 @@ static void test_icon_spacing(void)
        "Expected %d, got %d\n", MAKELONG(w, h), r);
 
     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
        "Expected %d, got %d\n", MAKELONG(w, h), r);
 
     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
+    if (r == 0)
+    {
+        /* version 4.0 */
+        win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
+        DestroyWindow(hwnd);
+        return;
+    }
     expect(MAKELONG(20,30), r);
 
     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
     expect(MAKELONG(20,30), r);
 
     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
@@ -1239,7 +1650,7 @@ static void test_color(void)
     COLORREF color;
     COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
 
     COLORREF color;
     COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
 
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
@@ -1277,6 +1688,11 @@ static void test_item_count(void)
 
     HWND hwnd;
     DWORD r;
 
     HWND hwnd;
     DWORD r;
+    HDC hdc;
+    HFONT hOldFont;
+    TEXTMETRICA tm;
+    RECT rect;
+    INT height;
 
     LVITEM item0;
     LVITEM item1;
 
     LVITEM item0;
     LVITEM item1;
@@ -1285,9 +1701,22 @@ static void test_item_count(void)
     static CHAR item1text[] = "item1";
     static CHAR item2text[] = "item2";
 
     static CHAR item1text[] = "item1";
     static CHAR item2text[] = "item2";
 
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     ok(hwnd != NULL, "failed to create a listview window\n");
 
+    /* resize in dpiaware manner to fit all 3 items added */
+    hdc = GetDC(0);
+    hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
+    GetTextMetricsA(hdc, &tm);
+    /* 2 extra pixels for bounds and header border */
+    height = tm.tmHeight + 2;
+    SelectObject(hdc, hOldFont);
+    ReleaseDC(0, hdc);
+
+    GetWindowRect(hwnd, &rect);
+    /* 3 items + 1 header + 1 to be sure */
+    MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     trace("test item count\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     trace("test item count\n");
@@ -1375,7 +1804,7 @@ static void test_item_position(void)
     static CHAR item1text[] = "item1";
     static CHAR item2text[] = "item2";
 
     static CHAR item1text[] = "item1";
     static CHAR item2text[] = "item2";
 
-    hwnd = create_custom_listview_control(LVS_ICON);
+    hwnd = create_listview_control(LVS_ICON);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
@@ -1440,7 +1869,7 @@ static void test_getorigin(void)
 
     position.x = position.y = 0;
 
 
     position.x = position.y = 0;
 
-    hwnd = create_custom_listview_control(LVS_ICON);
+    hwnd = create_listview_control(LVS_ICON);
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
@@ -1449,7 +1878,7 @@ static void test_getorigin(void)
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(hwnd);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(hwnd);
 
-    hwnd = create_custom_listview_control(LVS_SMALLICON);
+    hwnd = create_listview_control(LVS_SMALLICON);
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
@@ -1458,7 +1887,7 @@ static void test_getorigin(void)
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(hwnd);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(hwnd);
 
-    hwnd = create_custom_listview_control(LVS_LIST);
+    hwnd = create_listview_control(LVS_LIST);
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
@@ -1467,7 +1896,7 @@ static void test_getorigin(void)
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(hwnd);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(hwnd);
 
-    hwnd = create_custom_listview_control(LVS_REPORT);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     trace("test get origin results\n");
@@ -1496,6 +1925,7 @@ static void test_multiselect(void)
     BYTE kstate[256];
     select_task task;
     LONG_PTR style;
     BYTE kstate[256];
     select_task task;
     LONG_PTR style;
+    LVITEMA item;
 
     static struct t_select_task task_list[] = {
         { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
 
     static struct t_select_task task_list[] = {
         { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
@@ -1505,7 +1935,7 @@ static void test_multiselect(void)
     };
 
 
     };
 
 
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
 
     for (i=0;i<items;i++) {
            insert_item(hwnd, 0);
 
     for (i=0;i<items;i++) {
            insert_item(hwnd, 0);
@@ -1554,12 +1984,30 @@ static void test_multiselect(void)
     DestroyWindow(hwnd);
 
     /* make multiple selection, then switch to LVS_SINGLESEL */
     DestroyWindow(hwnd);
 
     /* make multiple selection, then switch to LVS_SINGLESEL */
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     for (i=0;i<items;i++) {
            insert_item(hwnd, 0);
     }
     item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
     expect(items,item_count);
     for (i=0;i<items;i++) {
            insert_item(hwnd, 0);
     }
     item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
     expect(items,item_count);
+
+    /* try with NULL pointer */
+    r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
+    expect(FALSE, r);
+
+    /* select all, check notifications */
+    ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+    r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, select_all_parent_seq,
+                "select all notification", FALSE);
+
     /* deselect all items */
     ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
     SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
     /* deselect all items */
     ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
     SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
@@ -1570,7 +2018,6 @@ static void test_multiselect(void)
     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
     expect(3, r);
     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
     expect(3, r);
     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
-todo_wine
     expect(-1, r);
 
     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
     expect(-1, r);
 
     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
@@ -1602,9 +2049,38 @@ todo_wine
     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
     expect(1, r);
     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
     expect(1, r);
     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
-todo_wine
     expect(-1, r);
 
     expect(-1, r);
 
+    /* try to select all on LVS_SINGLESEL */
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_SELECTED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+    SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
+
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(FALSE, r);
+
+    r = ListView_GetSelectedCount(hwnd);
+    expect(0, r);
+    r = ListView_GetSelectionMark(hwnd);
+    expect(-1, r);
+
+    /* try to deselect all on LVS_SINGLESEL */
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    item.stateMask = LVIS_SELECTED;
+    item.state     = 0;
+    r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, r);
+    r = ListView_GetSelectedCount(hwnd);
+    expect(0, r);
+
     DestroyWindow(hwnd);
 }
 
     DestroyWindow(hwnd);
 }
 
@@ -1613,24 +2089,22 @@ static void test_subitem_rect(void)
     HWND hwnd;
     DWORD r;
     LVCOLUMN col;
     HWND hwnd;
     DWORD r;
     LVCOLUMN col;
-    RECT rect;
+    RECT rect, rect2;
+    INT arr[3];
 
     /* test LVM_GETSUBITEMRECT for header */
 
     /* test LVM_GETSUBITEMRECT for header */
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     /* add some columns */
     memset(&col, 0, sizeof(LVCOLUMN));
     col.mask = LVCF_WIDTH;
     col.cx = 100;
     ok(hwnd != NULL, "failed to create a listview window\n");
     /* add some columns */
     memset(&col, 0, sizeof(LVCOLUMN));
     col.mask = LVCF_WIDTH;
     col.cx = 100;
-    r = -1;
     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
     expect(0, r);
     col.cx = 150;
     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
     expect(0, r);
     col.cx = 150;
-    r = -1;
     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
     expect(1, r);
     col.cx = 200;
     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
     expect(1, r);
     col.cx = 200;
-    r = -1;
     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
     expect(2, r);
     /* item = -1 means header, subitem index is 1 based */
     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
     expect(2, r);
     /* item = -1 means header, subitem index is 1 based */
@@ -1662,23 +2136,153 @@ todo_wine
 todo_wine
     expect(3, rect.top);
 
 todo_wine
     expect(3, rect.top);
 
-    DestroyWindow(hwnd);
+    /* item LVS_REPORT padding isn't applied to subitems */
+    insert_item(hwnd, 0);
 
 
-    /* try it for non LVS_REPORT style */
-    hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
-                         GetModuleHandle(NULL), 0);
     rect.left = LVIR_BOUNDS;
     rect.top  = 1;
     rect.left = LVIR_BOUNDS;
     rect.top  = 1;
-    rect.right = rect.bottom = -10;
-    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
-    ok(r == 0, "Expected not-null LRESULT\n");
-    /* rect is unchanged */
-    expect(0, rect.left);
-    expect(-10, rect.right);
-    expect(1, rect.top);
-    expect(-10, rect.bottom);
-    DestroyWindow(hwnd);
-}
+    rect.right = rect.bottom = 0;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r != 0, "Expected not-null LRESULT\n");
+    expect(100, rect.left);
+    expect(250, rect.right);
+
+    rect.left = LVIR_ICON;
+    rect.top  = 1;
+    rect.right = rect.bottom = 0;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r != 0, "Expected not-null LRESULT\n");
+    /* no icon attached - zero width rectangle, with no left padding */
+    expect(100, rect.left);
+    expect(100, rect.right);
+
+    rect.left = LVIR_LABEL;
+    rect.top  = 1;
+    rect.right = rect.bottom = 0;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r != 0, "Expected not-null LRESULT\n");
+    /* same as full LVIR_BOUNDS */
+    expect(100, rect.left);
+    expect(250, rect.right);
+
+    SendMessage(hwnd, LVM_SCROLL, 10, 0);
+
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 1;
+    rect.right = rect.bottom = 0;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r != 0, "Expected not-null LRESULT\n");
+    expect(90, rect.left);
+    expect(240, rect.right);
+
+    SendMessage(hwnd, LVM_SCROLL, -10, 0);
+
+    DestroyWindow(hwnd);
+
+    /* test subitem rects after re-arranging columns */
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    memset(&col, 0, sizeof(LVCOLUMN));
+    col.mask = LVCF_WIDTH;
+
+    col.cx = 100;
+    r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
+    expect(0, r);
+
+    col.cx = 200;
+    r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
+    expect(1, r);
+
+    col.cx = 300;
+    r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
+    expect(2, r);
+
+    insert_item(hwnd, 0);
+    insert_item(hwnd, 1);
+
+    /* wrong item is refused for main item */
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 0;
+    rect.right = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
+    ok(r == FALSE, "got %d\n", r);
+
+    /* for subitems rectangle is calculated even if there's no item added */
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 1;
+    rect.right = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
+    ok(r == TRUE, "got %d\n", r);
+
+    rect2.left = LVIR_BOUNDS;
+    rect2.top  = 1;
+    rect2.right = rect2.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
+todo_wine {
+    ok(r == TRUE, "got %d\n", r);
+    expect(rect.right, rect2.right);
+    expect(rect.left, rect2.left);
+    expect(rect.bottom, rect2.top);
+    ok(rect2.bottom > rect2.top, "expected not zero height\n");
+}
+
+    arr[0] = 1; arr[1] = 0; arr[2] = 2;
+    r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
+    expect(TRUE, r);
+
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 0;
+    rect.right = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r == TRUE, "got %d\n", r);
+    expect(0, rect.left);
+    expect(600, rect.right);
+
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 1;
+    rect.right = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r == TRUE, "got %d\n", r);
+    expect(0, rect.left);
+    expect(200, rect.right);
+
+    rect2.left = LVIR_BOUNDS;
+    rect2.top  = 1;
+    rect2.right = rect2.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
+    ok(r == TRUE, "got %d\n", r);
+    expect(0, rect2.left);
+    expect(200, rect2.right);
+    /* items are of the same height */
+    ok(rect2.top > 0, "expected positive item height\n");
+    expect(rect.bottom, rect2.top);
+    expect(rect.bottom * 2 - rect.top, rect2.bottom);
+
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 2;
+    rect.right = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
+    ok(r == TRUE, "got %d\n", r);
+    expect(300, rect.left);
+    expect(600, rect.right);
+
+    DestroyWindow(hwnd);
+
+    /* try it for non LVS_REPORT style */
+    hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
+                         GetModuleHandle(NULL), 0);
+    rect.left = LVIR_BOUNDS;
+    rect.top  = 1;
+    rect.right = rect.bottom = -10;
+    r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
+    ok(r == 0, "Expected not-null LRESULT\n");
+    /* rect is unchanged */
+    expect(0, rect.left);
+    expect(-10, rect.right);
+    expect(1, rect.top);
+    expect(-10, rect.bottom);
+    DestroyWindow(hwnd);
+}
 
 /* comparison callback for test_sorting */
 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
 
 /* comparison callback for test_sorting */
 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
@@ -1696,7 +2300,7 @@ static void test_sorting(void)
     static CHAR names[][5] = {"A", "B", "C", "D", "0"};
     CHAR buff[10];
 
     static CHAR names[][5] = {"A", "B", "C", "D", "0"};
     CHAR buff[10];
 
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     /* insert some items */
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     /* insert some items */
@@ -1746,7 +2350,7 @@ static void test_sorting(void)
     DestroyWindow(hwnd);
 
     /* switch to LVS_SORTASCENDING when some items added */
     DestroyWindow(hwnd);
 
     /* switch to LVS_SORTASCENDING when some items added */
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     item.mask = LVIF_TEXT;
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     item.mask = LVIF_TEXT;
@@ -1873,24 +2477,31 @@ static void test_ownerdata(void)
     LVITEMA item;
 
     /* it isn't possible to set LVS_OWNERDATA after creation */
     LVITEMA item;
 
     /* it isn't possible to set LVS_OWNERDATA after creation */
-    hwnd = create_listview_control(0);
-    ok(hwnd != NULL, "failed to create a listview window\n");
-    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
-    ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
+    if (g_is_below_5)
+    {
+        win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
+    }
+    else
+    {
+        hwnd = create_listview_control(LVS_REPORT);
+        ok(hwnd != NULL, "failed to create a listview window\n");
+        style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+        ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
 
 
-    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
-    ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
-    ok(ret == style, "Expected set GWL_STYLE to succeed\n");
-    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
+        ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
+        ok(ret == style, "Expected set GWL_STYLE to succeed\n");
+        ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
                 "try to switch to LVS_OWNERDATA seq", FALSE);
 
                 "try to switch to LVS_OWNERDATA seq", FALSE);
 
-    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
-    ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
-    DestroyWindow(hwnd);
+        style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+        ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
+        DestroyWindow(hwnd);
+    }
 
     /* try to set LVS_OWNERDATA after creation just having it */
 
     /* try to set LVS_OWNERDATA after creation just having it */
-    hwnd = create_listview_control(LVS_OWNERDATA);
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
     ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
     ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
@@ -1904,23 +2515,30 @@ static void test_ownerdata(void)
     DestroyWindow(hwnd);
 
     /* try to remove LVS_OWNERDATA after creation just having it */
     DestroyWindow(hwnd);
 
     /* try to remove LVS_OWNERDATA after creation just having it */
-    hwnd = create_listview_control(LVS_OWNERDATA);
-    ok(hwnd != NULL, "failed to create a listview window\n");
-    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
-    ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
+    if (g_is_below_5)
+    {
+        win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
+    }
+    else
+    {
+        hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+        ok(hwnd != NULL, "failed to create a listview window\n");
+        style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+        ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
 
 
-    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
-    ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
-    ok(ret == style, "Expected set GWL_STYLE to succeed\n");
-    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
+        ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
+        ok(ret == style, "Expected set GWL_STYLE to succeed\n");
+        ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
                 "try to switch to LVS_OWNERDATA seq", FALSE);
                 "try to switch to LVS_OWNERDATA seq", FALSE);
-    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
-    ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
-    DestroyWindow(hwnd);
+        style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+        ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
+        DestroyWindow(hwnd);
+    }
 
     /* try select an item */
 
     /* try select an item */
-    hwnd = create_listview_control(LVS_OWNERDATA);
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
     ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
     ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
@@ -1938,7 +2556,7 @@ static void test_ownerdata(void)
     DestroyWindow(hwnd);
 
     /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
     DestroyWindow(hwnd);
 
     /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
-    hwnd = create_listview_control(LVS_OWNERDATA);
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
     ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
     ok(hwnd != NULL, "failed to create a listview window\n");
     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
     ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
@@ -1952,6 +2570,224 @@ static void test_ownerdata(void)
     res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
     expect(FALSE, res);
     DestroyWindow(hwnd);
     res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
     expect(FALSE, res);
     DestroyWindow(hwnd);
+
+    /* check notifications after focused/selected changed */
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
+    ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
+                "ownerdata select notification", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
+                "ownerdata focus notification", TRUE);
+
+    /* select all, check notifications */
+    item.stateMask = LVIS_SELECTED;
+    item.state     = 0;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
+                "ownerdata select all notification", TRUE);
+
+    /* select all again, note that all items are selected already */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
+                "ownerdata select all notification", TRUE);
+    /* deselect all */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_SELECTED;
+    item.state     = 0;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
+                "ownerdata deselect all notification", TRUE);
+
+    /* select one, then deselect all */
+    item.stateMask = LVIS_SELECTED;
+    item.state     = LVIS_SELECTED;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, res);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_SELECTED;
+    item.state     = 0;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
+                "ownerdata select all notification", TRUE);
+
+    /* remove focused, try to focus all */
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, res);
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = 0;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    item.stateMask = LVIS_FOCUSED;
+    res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
+    expect(0, res);
+    /* setting all to focused returns failure value */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(FALSE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "ownerdata focus all notification", FALSE);
+    /* focus single item, remove all */
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = LVIS_FOCUSED;
+    res = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
+    expect(TRUE, res);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_FOCUSED;
+    item.state     = 0;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
+                "ownerdata remove focus all notification", TRUE);
+    /* set all cut */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_CUT;
+    item.state     = LVIS_CUT;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
+                "ownerdata cut all notification", TRUE);
+    /* all marked cut, try again */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    item.stateMask = LVIS_CUT;
+    item.state     = LVIS_CUT;
+    g_dump_itemchanged = TRUE;
+    res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
+    expect(TRUE, res);
+    g_dump_itemchanged = FALSE;
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
+                "ownerdata cut all notification #2", TRUE);
+
+    DestroyWindow(hwnd);
+
+    /* check notifications on LVM_GETITEM */
+    /* zero callback mask */
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+    ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_SELECTED;
+    item.mask      = LVIF_STATE;
+    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "ownerdata getitem selected state 1", FALSE);
+
+    /* non zero callback mask but not we asking for */
+    res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
+    expect(TRUE, res);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_SELECTED;
+    item.mask      = LVIF_STATE;
+    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "ownerdata getitem selected state 2", FALSE);
+
+    /* LVIS_OVERLAYMASK callback mask, asking for index */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_OVERLAYMASK;
+    item.mask      = LVIF_STATE;
+    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
+                "ownerdata getitem selected state 2", FALSE);
+
+    DestroyWindow(hwnd);
+
+    /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
+    ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
+    SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
+    DestroyWindow(hwnd);
+    /* apparently it's allowed to switch these style on after creation */
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
+    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
+    DestroyWindow(hwnd);
+
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
+    SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
+    style = GetWindowLongPtrA(hwnd, GWL_STYLE);
+    ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
+    DestroyWindow(hwnd);
 }
 
 static void test_norecompute(void)
 }
 
 static void test_norecompute(void)
@@ -1963,7 +2799,7 @@ static void test_norecompute(void)
     DWORD res;
 
     /* self containing control */
     DWORD res;
 
     /* self containing control */
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
     memset(&item, 0, sizeof(item));
     item.mask = LVIF_TEXT | LVIF_STATE;
     ok(hwnd != NULL, "failed to create a listview window\n");
     memset(&item, 0, sizeof(item));
     item.mask = LVIF_TEXT | LVIF_STATE;
@@ -2003,7 +2839,7 @@ static void test_norecompute(void)
     DestroyWindow(hwnd);
 
     /* LVS_OWNERDATA */
     DestroyWindow(hwnd);
 
     /* LVS_OWNERDATA */
-    hwnd = create_listview_control(LVS_OWNERDATA);
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     item.mask = LVIF_STATE;
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     item.mask = LVIF_STATE;
@@ -2032,7 +2868,7 @@ static void test_nosortheader(void)
     HWND hwnd, header;
     LONG_PTR style;
 
     HWND hwnd, header;
     LONG_PTR style;
 
-    hwnd = create_listview_control(0);
+    hwnd = create_listview_control(LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
@@ -2050,7 +2886,7 @@ static void test_nosortheader(void)
     DestroyWindow(hwnd);
 
     /* create with LVS_NOSORTHEADER */
     DestroyWindow(hwnd);
 
     /* create with LVS_NOSORTHEADER */
-    hwnd = create_listview_control(LVS_NOSORTHEADER);
+    hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
@@ -2068,34 +2904,1650 @@ static void test_nosortheader(void)
     DestroyWindow(hwnd);
 }
 
     DestroyWindow(hwnd);
 }
 
-START_TEST(listview)
+static void test_setredraw(void)
 {
 {
-    HMODULE hComctl32;
-    BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
+    HWND hwnd;
+    DWORD_PTR style;
+    DWORD ret;
+    HDC hdc;
+    RECT rect;
 
 
-    hComctl32 = GetModuleHandleA("comctl32.dll");
-    pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
-    if (pInitCommonControlsEx)
-    {
-        INITCOMMONCONTROLSEX iccex;
-        iccex.dwSize = sizeof(iccex);
-        iccex.dwICC  = ICC_LISTVIEW_CLASSES;
-        pInitCommonControlsEx(&iccex);
-    }
-    else
-        InitCommonControls();
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
 
 
-    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+    /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
+       ListView seems to handle it internally without DefWinProc */
+
+    /* default value first */
+    ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+    expect(0, ret);
+    /* disable */
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
+    ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+    expect(0, ret);
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
+    ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+    expect(0, ret);
+
+    /* check update rect after redrawing */
+    ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+    expect(0, ret);
+    InvalidateRect(hwnd, NULL, FALSE);
+    RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
+    rect.right = rect.bottom = 1;
+    GetUpdateRect(hwnd, &rect, FALSE);
+    expect(0, rect.right);
+    expect(0, rect.bottom);
+
+    /* WM_ERASEBKGND */
+    hdc = GetWindowDC(hwndparent);
+    ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
+    expect(TRUE, ret);
+    ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+    expect(0, ret);
+    ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
+    expect(TRUE, ret);
+    ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+    expect(0, ret);
+    ReleaseDC(hwndparent, hdc);
 
 
+    /* check notification messages to show that repainting is disabled */
+    ret = SendMessage(hwnd, LVM_SETITEMCOUNT, 1, 0);
+    expect(TRUE, ret);
+    ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+    expect(0, ret);
     flush_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);
+
+    InvalidateRect(hwnd, NULL, TRUE);
+    UpdateWindow(hwnd);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "redraw after WM_SETREDRAW (FALSE)", FALSE);
+
+    ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
+    expect(TRUE, ret);
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    InvalidateRect(hwnd, NULL, TRUE);
+    UpdateWindow(hwnd);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
 
 
-    test_images();
-    test_checkboxes();
-    test_items();
-    test_create();
+    /* message isn't forwarded to header */
+    subclass_header(hwnd);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+    expect(0, ret);
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
+                "WM_SETREDRAW: not forwarded to header", FALSE);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_hittest(void)
+{
+    HWND hwnd;
+    DWORD r;
+    RECT bounds;
+    LVITEMA item;
+    static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
+    POINT pos;
+    INT x, y;
+    HIMAGELIST himl, himl2;
+    HBITMAP hbmp;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    /* LVS_REPORT with a single subitem (2 columns) */
+    insert_column(hwnd, 0);
+    insert_column(hwnd, 1);
+    insert_item(hwnd, 0);
+
+    item.iSubItem = 0;
+    /* the only purpose of that line is to be as long as a half item rect */
+    item.pszText  = text;
+    r = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
+    expect(TRUE, r);
+    r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
+    expect(TRUE, r);
+
+    memset(&bounds, 0, sizeof(bounds));
+    bounds.left = LVIR_BOUNDS;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
+    ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
+    ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
+    expect(TRUE, r);
+
+    /* LVS_EX_FULLROWSELECT not set, no icons attached */
+
+    /* outside columns by x position - valid is [0, 199] */
+    x = -1;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
+
+    x = pos.x + 50; /* column half width */
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    x = pos.x + 150; /* outside column */
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    /* outside possible client rectangle (to right) */
+    x = pos.x + 500;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
+    /* subitem returned with -1 item too */
+    x = pos.x + 150;
+    y = -10;
+    test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
+    /* parent client area is 100x100 by default */
+    MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
+    x = pos.x + 150; /* outside column */
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    /* the same with LVS_EX_FULLROWSELECT */
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
+    x = pos.x + 150; /* outside column */
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
+    x = pos.x + 150; /* outside column */
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
+    /* outside possible client rectangle (to right) */
+    x = pos.x + 500;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
+    /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
+    himl = ImageList_Create(16, 16, 0, 4, 4);
+    ok(himl != NULL, "failed to create imagelist\n");
+    hbmp = CreateBitmap(16, 16, 1, 1, NULL);
+    ok(hbmp != NULL, "failed to create bitmap\n");
+    r = ImageList_Add(himl, hbmp, 0);
+    ok(r == 0, "should be zero\n");
+    hbmp = CreateBitmap(16, 16, 1, 1, NULL);
+    ok(hbmp != NULL, "failed to create bitmap\n");
+    r = ImageList_Add(himl, hbmp, 0);
+    ok(r == 1, "should be one\n");
+
+    r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
+    ok(r == 0, "should return zero\n");
+
+    item.mask = LVIF_IMAGE;
+    item.iImage = 0;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+    /* on state icon */
+    x = pos.x + 8;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
+
+    /* state icons indices are 1 based, check with valid index */
+    item.mask = LVIF_STATE;
+    item.state = INDEXTOSTATEIMAGEMASK(1);
+    item.stateMask = LVIS_STATEIMAGEMASK;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+    /* on state icon */
+    x = pos.x + 8;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
+
+    himl2 = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
+    ok(himl2 == himl, "should return handle\n");
+
+    r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
+    ok(r == 0, "should return zero\n");
+    /* on item icon */
+    x = pos.x + 8;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
+    y = (bounds.bottom - bounds.top) / 2;
+    test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_getviewrect(void)
+{
+    HWND hwnd;
+    DWORD r;
+    RECT rect;
+    LVITEMA item;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    /* empty */
+    r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+
+    insert_column(hwnd, 0);
+    insert_column(hwnd, 1);
+
+    memset(&item, 0, sizeof(item));
+    item.iItem = 0;
+    item.iSubItem = 0;
+    SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+
+    r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
+    expect(TRUE, r);
+    r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
+    expect(TRUE, r);
+
+    rect.left = rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* left is set to (2e31-1) - XP SP2 */
+    expect(0, rect.right);
+    expect(0, rect.top);
+    expect(0, rect.bottom);
+
+    /* switch to LVS_ICON */
+    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~LVS_REPORT);
+
+    rect.left = rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    expect(0, rect.left);
+    expect(0, rect.top);
+    /* precise value differs for 2k, XP and Vista */
+    ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
+    ok(rect.right  > 0, "Expected positive right value, got %d\n", rect.right);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_getitemposition(void)
+{
+    HWND hwnd, header;
+    DWORD r;
+    POINT pt;
+    RECT rect;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = subclass_header(hwnd);
+
+    /* LVS_REPORT, single item, no columns added */
+    insert_item(hwnd, 0);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    pt.x = pt.y = -1;
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
+    expect(TRUE, r);
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
+
+    /* LVS_REPORT, single item, single column */
+    insert_column(hwnd, 0);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    pt.x = pt.y = -1;
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
+    expect(TRUE, r);
+    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
+
+    memset(&rect, 0, sizeof(rect));
+    SendMessage(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
+    /* some padding? */
+    expect(2, pt.x);
+    /* offset by header height */
+    expect(rect.bottom - rect.top, pt.y);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_columnscreation(void)
+{
+    HWND hwnd, header;
+    DWORD r;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    insert_item(hwnd, 0);
+
+    /* headers columns aren't created automatically */
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "Expected header handle\n");
+    r = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
+    expect(0, r);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_getitemrect(void)
+{
+    HWND hwnd;
+    HIMAGELIST himl;
+    HBITMAP hbm;
+    RECT rect;
+    DWORD r;
+    LVITEMA item;
+    LVCOLUMNA col;
+    INT order[2];
+    POINT pt;
+
+    /* rectangle isn't empty for empty text items */
+    hwnd = create_listview_control(LVS_LIST);
+    memset(&item, 0, sizeof(item));
+    item.mask = 0;
+    item.iItem = 0;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    expect(0, r);
+    rect.left = LVIR_LABEL;
+    SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(0, rect.left);
+    expect(0, rect.top);
+    todo_wine expect(96, rect.right);
+    DestroyWindow(hwnd);
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    /* empty item */
+    memset(&item, 0, sizeof(item));
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    expect(0, r);
+
+    rect.left = LVIR_BOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+
+    /* zero width rectangle with no padding */
+    expect(0, rect.left);
+    expect(0, rect.right);
+
+    insert_column(hwnd, 0);
+    insert_column(hwnd, 1);
+
+    col.mask = LVCF_WIDTH;
+    col.cx   = 50;
+    r = SendMessage(hwnd, LVM_SETCOLUMN, 0, (LPARAM)&col);
+    expect(TRUE, r);
+
+    col.mask = LVCF_WIDTH;
+    col.cx   = 100;
+    r = SendMessage(hwnd, LVM_SETCOLUMN, 1, (LPARAM)&col);
+    expect(TRUE, r);
+
+    rect.left = LVIR_BOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+
+    /* still no left padding */
+    expect(0, rect.left);
+    expect(150, rect.right);
+
+    rect.left = LVIR_SELECTBOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding */
+    expect(2, rect.left);
+
+    rect.left = LVIR_LABEL;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding, column width */
+    expect(2, rect.left);
+    expect(50, rect.right);
+
+    /* no icons attached */
+    rect.left = LVIR_ICON;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding */
+    expect(2, rect.left);
+    expect(2, rect.right);
+
+    /* change order */
+    order[0] = 1; order[1] = 0;
+    r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
+    expect(TRUE, r);
+    pt.x = -1;
+    r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
+    expect(TRUE, r);
+    /* 1 indexed column width + padding */
+    expect(102, pt.x);
+    /* rect is at zero too */
+    rect.left = LVIR_BOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    expect(0, rect.left);
+    /* just width sum */
+    expect(150, rect.right);
+
+    rect.left = LVIR_SELECTBOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* column width + padding */
+    expect(102, rect.left);
+
+    /* back to initial order */
+    order[0] = 0; order[1] = 1;
+    r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
+    expect(TRUE, r);
+
+    /* state icons */
+    himl = ImageList_Create(16, 16, 0, 2, 2);
+    ok(himl != NULL, "failed to create imagelist\n");
+    hbm = CreateBitmap(16, 16, 1, 1, NULL);
+    ok(hbm != NULL, "failed to create bitmap\n");
+    r = ImageList_Add(himl, hbm, 0);
+    ok(r == 0, "should be zero\n");
+    hbm = CreateBitmap(16, 16, 1, 1, NULL);
+    ok(hbm != NULL, "failed to create bitmap\n");
+    r = ImageList_Add(himl, hbm, 0);
+    ok(r == 1, "should be one\n");
+
+    r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
+    ok(r == 0, "should return zero\n");
+
+    item.mask = LVIF_STATE;
+    item.state = INDEXTOSTATEIMAGEMASK(1);
+    item.stateMask = LVIS_STATEIMAGEMASK;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    /* icon bounds */
+    rect.left = LVIR_ICON;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + stateicon width */
+    expect(18, rect.left);
+    expect(18, rect.right);
+    /* label bounds */
+    rect.left = LVIR_LABEL;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + stateicon width -> column width */
+    expect(18, rect.left);
+    expect(50, rect.right);
+
+    r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
+    ok(r != 0, "should return current list handle\n");
+
+    r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
+    ok(r == 0, "should return zero\n");
+
+    item.mask = LVIF_STATE | LVIF_IMAGE;
+    item.iImage = 1;
+    item.state = 0;
+    item.stateMask = ~0;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    /* icon bounds */
+    rect.left = LVIR_ICON;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding, icon width */
+    expect(2, rect.left);
+    expect(18, rect.right);
+    /* label bounds */
+    rect.left = LVIR_LABEL;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + icon width -> column width */
+    expect(18, rect.left);
+    expect(50, rect.right);
+
+    /* select bounds */
+    rect.left = LVIR_SELECTBOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding, column width */
+    expect(2, rect.left);
+    expect(50, rect.right);
+
+    /* try with indentation */
+    item.mask = LVIF_INDENT;
+    item.iIndent = 1;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    /* bounds */
+    rect.left = LVIR_BOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + 1 icon width, column width */
+    expect(0, rect.left);
+    expect(150, rect.right);
+
+    /* select bounds */
+    rect.left = LVIR_SELECTBOUNDS;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + 1 icon width, column width */
+    expect(2 + 16, rect.left);
+    expect(50, rect.right);
+
+    /* label bounds */
+    rect.left = LVIR_LABEL;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + 2 icon widths, column width */
+    expect(2 + 16*2, rect.left);
+    expect(50, rect.right);
+
+    /* icon bounds */
+    rect.left = LVIR_ICON;
+    rect.right = rect.top = rect.bottom = -1;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
+    expect(TRUE, r);
+    /* padding + 1 icon width indentation, icon width */
+    expect(2 + 16, rect.left);
+    expect(34, rect.right);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_editbox(void)
+{
+    static CHAR testitemA[]  = "testitem";
+    static CHAR testitem1A[] = "testitem_quitelongname";
+    static CHAR buffer[25];
+    HWND hwnd, hwndedit, hwndedit2, header;
+    LVITEMA item;
+    DWORD r;
+
+    hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    insert_column(hwnd, 0);
+
+    memset(&item, 0, sizeof(item));
+    item.mask = LVIF_TEXT;
+    item.pszText = testitemA;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    expect(0, r);
+
+    /* test notifications without edit created */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
+    /* same thing but with valid window */
+    hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
+                10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
+    DestroyWindow(hwndedit);
+
+    /* setting focus is necessary */
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+
+    /* test children Z-order after Edit box created */
+    header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "Expected header to be created\n");
+    ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
+    ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
+
+    /* modify initial string */
+    r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
+    expect(TRUE, r);
+
+    /* edit window is resized and repositioned,
+       check again for Z-order - it should be preserved */
+    ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
+    ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
+
+    /* return focus to listview */
+    SetFocus(hwnd);
+
+    memset(&item, 0, sizeof(item));
+    item.mask = LVIF_TEXT;
+    item.pszText = buffer;
+    item.cchTextMax = sizeof(buffer);
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
+
+    /* send LVM_EDITLABEL on already created edit */
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    /* focus will be set to edit */
+    ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
+    hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
+
+    /* creating label disabled when control isn't focused */
+    SetFocus(0);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
+
+    /* check EN_KILLFOCUS handling */
+    memset(&item, 0, sizeof(item));
+    item.pszText = testitemA;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    /* modify edit and notify control that it lost focus */
+    r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
+    expect(TRUE, r);
+    r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
+    expect(0, r);
+    memset(&item, 0, sizeof(item));
+    item.pszText = buffer;
+    item.cchTextMax = sizeof(buffer);
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
+    expect(lstrlen(item.pszText), r);
+    ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
+    ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
+    /* end edit without saving */
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
+                "edit box - end edit, no change, escape", TRUE);
+    /* end edit with saving */
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
+                "edit box - end edit, no change, return", TRUE);
+
+    memset(&item, 0, sizeof(item));
+    item.pszText = buffer;
+    item.cchTextMax = sizeof(buffer);
+    item.iItem = 0;
+    item.iSubItem = 0;
+    r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
+    expect(lstrlen(item.pszText), r);
+    ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
+
+    /* LVM_EDITLABEL with -1 destroys current edit */
+    hwndedit = (HWND)SendMessage(hwnd, LVM_GETEDITCONTROL, 0, 0);
+    ok(hwndedit == NULL, "Expected Edit window not to be created\n");
+    /* no edit present */
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
+    ok(hwndedit == NULL, "Expected Edit window not to be created\n");
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    /* edit present */
+    ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
+    hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
+    ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
+    ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
+    ok(GetFocus() == hwnd, "Expected List to be focused\n");
+    /* check another negative value */
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
+    hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -2, 0);
+    ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
+    ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
+    ok(GetFocus() == hwnd, "Expected List to be focused\n");
+    /* and value greater than max item index */
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, r, 0);
+    ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
+    ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
+    ok(GetFocus() == hwnd, "Expected List to be focused\n");
+
+    /* messaging tests */
+    SetFocus(hwnd);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    blockEdit = FALSE;
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    /* testing only sizing messages */
+    ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
+                "edit box create - sizing", FALSE);
+
+    /* WM_COMMAND with EN_KILLFOCUS isn't forwared to parent */
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
+                "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_notifyformat(void)
+{
+    HWND hwnd, header;
+    DWORD r;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
+       CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
+    r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
+    /* set */
+    r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
+    expect(0, r);
+    r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    if (r == 1)
+    {
+        r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
+        expect(1, r);
+        r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+        expect(0, r);
+    }
+    else
+    {
+        win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+
+    DestroyWindow(hwnd);
+
+    /* test failure in parent WM_NOTIFYFORMAT  */
+    notifyFormat = 0;
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "expected header to be created\n");
+    r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
+    r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
+    ok(r != 0, "Expected valid format\n");
+
+    notifyFormat = NFR_UNICODE;
+    r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
+    expect(NFR_UNICODE, r);
+    r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
+
+    notifyFormat = NFR_ANSI;
+    r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
+    expect(NFR_ANSI, r);
+    r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
+
+    DestroyWindow(hwnd);
+
+    /* try different unicode window combination and defaults */
+    if (!GetModuleHandleW(NULL))
+    {
+        win_skip("Additional notify format tests are incompatible with Win9x\n");
+        return;
+    }
+
+    hwndparentW = create_parent_window(TRUE);
+    ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
+    if (!IsWindow(hwndparentW))  return;
+
+    notifyFormat = -1;
+    hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "expected header to be created\n");
+    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    DestroyWindow(hwnd);
+    /* receiving error code defaulting to ansi */
+    notifyFormat = 0;
+    hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "expected header to be created\n");
+    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    DestroyWindow(hwnd);
+    /* receiving ansi code from unicode window, use it */
+    notifyFormat = NFR_ANSI;
+    hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "expected header to be created\n");
+    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    DestroyWindow(hwnd);
+    /* unicode listview with ansi parent window */
+    notifyFormat = -1;
+    hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "expected header to be created\n");
+    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    DestroyWindow(hwnd);
+    /* unicode listview with ansi parent window, return error code */
+    notifyFormat = 0;
+    hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "expected header to be created\n");
+    r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
+    expect(0, r);
+    r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
+    expect(1, r);
+    DestroyWindow(hwnd);
+
+    DestroyWindow(hwndparentW);
+}
+
+static void test_indentation(void)
+{
+    HWND hwnd;
+    LVITEMA item;
+    DWORD r;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    memset(&item, 0, sizeof(item));
+    item.mask = LVIF_INDENT;
+    item.iItem = 0;
+    item.iIndent = I_INDENTCALLBACK;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
+    expect(0, r);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    item.iItem = 0;
+    item.mask = LVIF_INDENT;
+    r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
+                "get indent dispinfo", FALSE);
+
+    DestroyWindow(hwnd);
+}
+
+static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
+{
+    return 0;
+}
+
+static BOOL is_below_comctl_5(void)
+{
+    HWND hwnd;
+    BOOL ret;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    insert_item(hwnd, 0);
+
+    ret = SendMessage(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
+
+    DestroyWindow(hwnd);
+
+    return !ret;
+}
+
+static void test_get_set_view(void)
+{
+    HWND hwnd;
+    DWORD ret;
+    DWORD_PTR style;
+
+    /* test style->view mapping */
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
+    expect(LV_VIEW_DETAILS, ret);
+
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    /* LVS_ICON == 0 */
+    SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_REPORT);
+    ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
+    expect(LV_VIEW_ICON, ret);
+
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_SMALLICON);
+    ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
+    expect(LV_VIEW_SMALLICON, ret);
+
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    SetWindowLongPtr(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
+    ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
+    expect(LV_VIEW_LIST, ret);
+
+    /* switching view doesn't touch window style */
+    ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
+    expect(1, ret);
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    ok(style & LVS_LIST, "Expected style to be preserved\n");
+    ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
+    expect(1, ret);
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    ok(style & LVS_LIST, "Expected style to be preserved\n");
+    ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
+    expect(1, ret);
+    style = GetWindowLongPtr(hwnd, GWL_STYLE);
+    ok(style & LVS_LIST, "Expected style to be preserved\n");
+
+    DestroyWindow(hwnd);
+}
+
+static void test_canceleditlabel(void)
+{
+    HWND hwnd, hwndedit;
+    DWORD ret;
+    CHAR buff[10];
+    LVITEMA itema;
+    static CHAR test[] = "test";
+    static const CHAR test1[] = "test1";
+
+    hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    insert_item(hwnd, 0);
+
+    /* try without edit created */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
+    expect(TRUE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "cancel edit label without edit", FALSE);
+
+    /* cancel without data change */
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected edit control to be created\n");
+    ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
+    expect(TRUE, ret);
+    ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
+
+    /* cancel after data change */
+    memset(&itema, 0, sizeof(itema));
+    itema.pszText = test;
+    ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
+    expect(TRUE, ret);
+    SetFocus(hwnd);
+    hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
+    ok(IsWindow(hwndedit), "Expected edit control to be created\n");
+    ret = SetWindowText(hwndedit, test1);
+    ok(ret != 0, "Expected edit text to change\n");
+    ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
+    expect(TRUE, ret);
+    ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
+    memset(&itema, 0, sizeof(itema));
+    itema.pszText = buff;
+    itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
+    ret = SendMessage(hwnd, LVM_GETITEMTEXT, 0, (LPARAM)&itema);
+    expect(5, ret);
+    ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
+
+    DestroyWindow(hwnd);
+}
+
+static void test_mapidindex(void)
+{
+    HWND hwnd;
+    DWORD ret;
+
+    /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
+    hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    insert_item(hwnd, 0);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
+    expect(-1, ret);
+    DestroyWindow(hwnd);
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+
+    /* LVM_MAPINDEXTOID with invalid index */
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
+    expect(-1, ret);
+
+    insert_item(hwnd, 0);
+    insert_item(hwnd, 1);
+
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0);
+    expect(-1, ret);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0);
+    expect(-1, ret);
+
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
+    expect(1, ret);
+    /* remove 0 indexed item, id retained */
+    SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
+    expect(1, ret);
+    /* new id starts from previous value */
+    insert_item(hwnd, 1);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
+    expect(2, ret);
+
+    /* get index by id */
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0);
+    expect(-1, ret);
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0);
+    expect(-1, ret);
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0);
+    expect(1, ret);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_getitemspacing(void)
+{
+    HWND hwnd;
+    DWORD ret;
+    INT cx, cy;
+    HIMAGELIST himl;
+    HBITMAP hbmp;
+    LVITEMA itema;
+
+    cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
+    cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
+
+    /* LVS_ICON */
+    hwnd = create_listview_control(LVS_ICON);
+    ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
+todo_wine {
+    expect(cx, LOWORD(ret));
+    expect(cy, HIWORD(ret));
+}
+    /* now try with icons */
+    himl = ImageList_Create(40, 40, 0, 4, 4);
+    ok(himl != NULL, "failed to create imagelist\n");
+    hbmp = CreateBitmap(40, 40, 1, 1, NULL);
+    ok(hbmp != NULL, "failed to create bitmap\n");
+    ret = ImageList_Add(himl, hbmp, 0);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
+    expect(0, ret);
+
+    itema.mask = LVIF_IMAGE;
+    itema.iImage = 0;
+    itema.iItem = 0;
+    itema.iSubItem = 0;
+    ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
+todo_wine {
+    /* spacing + icon size returned */
+    expect(cx + 40, LOWORD(ret));
+    expect(cy + 40, HIWORD(ret));
+}
+    DestroyWindow(hwnd);
+    /* LVS_SMALLICON */
+    hwnd = create_listview_control(LVS_SMALLICON);
+    ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
+todo_wine {
+    expect(cx, LOWORD(ret));
+    expect(cy, HIWORD(ret));
+}
+    DestroyWindow(hwnd);
+    /* LVS_REPORT */
+    hwnd = create_listview_control(LVS_REPORT);
+    ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
+todo_wine {
+    expect(cx, LOWORD(ret));
+    expect(cy, HIWORD(ret));
+}
+    DestroyWindow(hwnd);
+    /* LVS_LIST */
+    hwnd = create_listview_control(LVS_LIST);
+    ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
+todo_wine {
+    expect(cx, LOWORD(ret));
+    expect(cy, HIWORD(ret));
+}
+    DestroyWindow(hwnd);
+}
+
+static void test_getcolumnwidth(void)
+{
+    HWND hwnd;
+    DWORD ret;
+    DWORD_PTR style;
+    LVCOLUMNA col;
+    LVITEMA itema;
+
+    /* default column width */
+    hwnd = create_listview_control(LVS_ICON);
+    ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
+    expect(0, ret);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    SetWindowLong(hwnd, GWL_STYLE, style | LVS_LIST);
+    ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
+    todo_wine expect(8, ret);
+    style = GetWindowLong(hwnd, GWL_STYLE) & ~LVS_LIST;
+    SetWindowLong(hwnd, GWL_STYLE, style | LVS_REPORT);
+    col.mask = 0;
+    ret = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
+    expect(10, ret);
+    DestroyWindow(hwnd);
+
+    /* default column width with item added */
+    hwnd = create_listview_control(LVS_LIST);
+    memset(&itema, 0, sizeof(itema));
+    SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
+    ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
+    todo_wine expect(96, ret);
+    DestroyWindow(hwnd);
+}
+
+static void test_scrollnotify(void)
+{
+    HWND hwnd;
+    DWORD ret;
+
+    hwnd = create_listview_control(LVS_REPORT);
+
+    insert_column(hwnd, 0);
+    insert_column(hwnd, 1);
+    insert_item(hwnd, 0);
+
+    /* make it scrollable - resize */
+    ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
+    expect(TRUE, ret);
+    ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
+    expect(TRUE, ret);
+
+    /* try with dummy call */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessage(hwnd, LVM_SCROLL, 0, 0);
+    expect(TRUE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
+                "scroll notify 1", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessage(hwnd, LVM_SCROLL, 1, 0);
+    expect(TRUE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
+                "scroll notify 2", TRUE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ret = SendMessage(hwnd, LVM_SCROLL, 1, 1);
+    expect(TRUE, ret);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
+                "scroll notify 3", TRUE);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_LVS_EX_TRANSPARENTBKGND(void)
+{
+    HWND hwnd;
+    DWORD ret;
+    HDC hdc;
+
+    hwnd = create_listview_control(LVS_REPORT);
+
+    ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
+    expect(TRUE, ret);
+
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
+                                                    LVS_EX_TRANSPARENTBKGND);
+
+    ret = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
+    if (ret != CLR_NONE)
+    {
+        win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+
+    /* try to set some back color and check this style bit */
+    ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
+    expect(TRUE, ret);
+    ret = SendMessage(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+    ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
+
+    /* now test what this style actually does */
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
+                                                    LVS_EX_TRANSPARENTBKGND);
+
+    hdc = GetWindowDC(hwndparent);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
+                "LVS_EX_TRANSPARENTBKGND parent", FALSE);
+
+    ReleaseDC(hwndparent, hdc);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_approximate_viewrect(void)
+{
+    HWND hwnd;
+    DWORD ret;
+    HIMAGELIST himl;
+    HBITMAP hbmp;
+    LVITEMA itema;
+    static CHAR test[] = "abracadabra, a very long item label";
+
+    hwnd = create_listview_control(LVS_ICON);
+    himl = ImageList_Create(40, 40, 0, 4, 4);
+    ok(himl != NULL, "failed to create imagelist\n");
+    hbmp = CreateBitmap(40, 40, 1, 1, NULL);
+    ok(hbmp != NULL, "failed to create bitmap\n");
+    ret = ImageList_Add(himl, hbmp, 0);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
+    expect(0, ret);
+
+    itema.mask = LVIF_IMAGE;
+    itema.iImage = 0;
+    itema.iItem = 0;
+    itema.iSubItem = 0;
+    ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
+    expect(0, ret);
+
+    ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
+    if (ret == 0)
+    {
+        /* version 4.0 */
+        win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
+        return;
+    }
+
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
+    ok(MAKELONG(77,827)==ret,"Incorrect Approximate rect\n");
+
+    ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
+    ok(MAKELONG(102,302)==ret,"Incorrect Approximate rect\n");
+
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
+    ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
+
+    itema.pszText = test;
+    ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
+    expect(TRUE, ret);
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
+    ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
+
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
+    ok(MAKELONG(52,2)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
+    ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
+    ok(MAKELONG(102,52)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
+    ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
+    ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
+    ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
+    ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n");
+    ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
+    ok(MAKELONG(152,152)==ret,"Incorrect Approximate rect\n");
+
+    DestroyWindow(hwnd);
+}
+
+static void test_finditem(void)
+{
+    LVFINDINFOA fi;
+    static char f[5];
+    HWND hwnd;
+    DWORD r;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    insert_item(hwnd, 0);
+
+    memset(&fi, 0, sizeof(fi));
+
+    /* full string search, inserted text was "foo" */
+    strcpy(f, "foo");
+    fi.flags = LVFI_STRING;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+    /* partial string search, inserted text was "foo" */
+    strcpy(f, "fo");
+    fi.flags = LVFI_STRING | LVFI_PARTIAL;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+    /* partial string search, part after start char */
+    strcpy(f, "oo");
+    fi.flags = LVFI_STRING | LVFI_PARTIAL;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(-1, r);
+
+    /* try with LVFI_SUBSTRING */
+    strcpy(f, "fo");
+    fi.flags = LVFI_SUBSTRING;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    if (r == -1)
+    {
+        win_skip("LVFI_SUBSTRING not supported\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+    expect(0, r);
+    strcpy(f, "f");
+    fi.flags = LVFI_SUBSTRING;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+    strcpy(f, "o");
+    fi.flags = LVFI_SUBSTRING;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(-1, r);
+
+    strcpy(f, "f");
+    fi.flags = LVFI_SUBSTRING | LVFI_STRING;
+    fi.psz = f;
+    r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
+    expect(0, r);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_LVS_EX_HEADERINALLVIEWS(void)
+{
+    HWND hwnd, header;
+    DWORD style;
+
+    hwnd = create_listview_control(LVS_ICON);
+
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
+                                                    LVS_EX_HEADERINALLVIEWS);
+
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    if (!IsWindow(header))
+    {
+        win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+
+    /* LVS_NOCOLUMNHEADER works as before */
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
+    style = GetWindowLongA(header, GWL_STYLE);
+    ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
+    style = GetWindowLongA(header, GWL_STYLE);
+    ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
+
+    /* try to remove style */
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "Expected header to be created\n");
+    style = GetWindowLongA(header, GWL_STYLE);
+    ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
+
+    DestroyWindow(hwnd);
+
+    /* check other styles */
+    hwnd = create_listview_control(LVS_LIST);
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
+                                                    LVS_EX_HEADERINALLVIEWS);
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "Expected header to be created\n");
+    DestroyWindow(hwnd);
+
+    hwnd = create_listview_control(LVS_SMALLICON);
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
+                                                    LVS_EX_HEADERINALLVIEWS);
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "Expected header to be created\n");
+    DestroyWindow(hwnd);
+
+    hwnd = create_listview_control(LVS_REPORT);
+    SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
+                                                    LVS_EX_HEADERINALLVIEWS);
+    header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
+    ok(IsWindow(header), "Expected header to be created\n");
+    DestroyWindow(hwnd);
+}
+
+static void test_hover(void)
+{
+    HWND hwnd;
+    DWORD r;
+
+    hwnd = create_listview_control(LVS_ICON);
+
+    /* test WM_MOUSEHOVER forwarding */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
+    g_block_hover = TRUE;
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
+    expect(0, r);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
+    g_block_hover = FALSE;
+
+    r = SendMessage(hwnd, LVM_SETHOVERTIME, 0, 500);
+    expect(HOVER_DEFAULT, r);
+    r = SendMessage(hwnd, LVM_GETHOVERTIME, 0, 0);
+    expect(500, r);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_destroynotify(void)
+{
+    HWND hwnd;
+
+    hwnd = create_listview_control(LVS_REPORT);
+    ok(hwnd != NULL, "failed to create listview window\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hwnd);
+    ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
+}
+
+static void test_header_notification(void)
+{
+    HWND list, header;
+    HDITEMA item;
+    NMHEADER nmh;
+    LVCOLUMNA col;
+    LRESULT ret;
+
+    list = create_listview_control(LVS_REPORT);
+    ok(list != 0, "failed to create listview window\n");
+
+    memset(&col, 0, sizeof(col));
+    col.mask = LVCF_WIDTH;
+    col.cx = 100;
+    ret = SendMessage(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
+    ok(!ret, "expected 0, got %ld\n", ret);
+
+    header = subclass_header(list);
+
+    ret = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
+    ok(ret == 1, "expected header item count 1, got %ld\n", ret);
+
+    memset(&item, 0, sizeof(item));
+    item.mask = HDI_WIDTH;
+    ret = SendMessage(header, HDM_GETITEMA, 0, (LPARAM)&item);
+    ok(ret, "HDM_GETITEM failed\n");
+    ok(item.cxy == 100, "expected 100, got %d\n", item.cxy);
+
+    nmh.hdr.hwndFrom = header;
+    nmh.hdr.idFrom = GetWindowLongPtr(header, GWLP_ID);
+    nmh.hdr.code = HDN_ITEMCHANGEDA;
+    nmh.iItem = 0;
+    nmh.iButton = 0;
+    item.mask = HDI_WIDTH;
+    item.cxy = 50;
+    nmh.pitem = &item;
+    ret = SendMessage(list, WM_NOTIFY, 0, (LPARAM)&nmh);
+    ok(!ret, "WM_NOTIFY/HDN_ITEMCHANGED failed\n");
+
+    DestroyWindow(list);
+}
+
+static void test_createdragimage(void)
+{
+    HIMAGELIST himl;
+    POINT pt;
+    HWND list;
+
+    list = create_listview_control(LVS_ICON);
+    ok(list != 0, "failed to create listview window\n");
+
+    insert_item(list, 0);
+
+    /* NULL point */
+    himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
+    ok(himl == NULL, "got %p\n", himl);
+
+    himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
+    ok(himl != NULL, "got %p\n", himl);
+    ImageList_Destroy(himl);
+
+    DestroyWindow(list);
+}
+
+START_TEST(listview)
+{
+    HMODULE hComctl32;
+    BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
+
+    ULONG_PTR ctx_cookie;
+    HANDLE hCtx;
+    HWND hwnd;
+
+    hComctl32 = GetModuleHandleA("comctl32.dll");
+    pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
+    if (pInitCommonControlsEx)
+    {
+        INITCOMMONCONTROLSEX iccex;
+        iccex.dwSize = sizeof(iccex);
+        iccex.dwICC  = ICC_LISTVIEW_CLASSES;
+        pInitCommonControlsEx(&iccex);
+    }
+    else
+        InitCommonControls();
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    hwndparent = create_parent_window(FALSE);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    g_is_below_5 = is_below_comctl_5();
+
+    test_header_notification();
+    test_images();
+    test_checkboxes();
+    test_items();
+    test_create();
     test_redraw();
     test_customdraw();
     test_icon_spacing();
     test_redraw();
     test_customdraw();
     test_icon_spacing();
@@ -2105,9 +4557,58 @@ START_TEST(listview)
     test_columns();
     test_getorigin();
     test_multiselect();
     test_columns();
     test_getorigin();
     test_multiselect();
+    test_getitemrect();
     test_subitem_rect();
     test_sorting();
     test_ownerdata();
     test_norecompute();
     test_nosortheader();
     test_subitem_rect();
     test_sorting();
     test_ownerdata();
     test_norecompute();
     test_nosortheader();
+    test_setredraw();
+    test_hittest();
+    test_getviewrect();
+    test_getitemposition();
+    test_columnscreation();
+    test_editbox();
+    test_notifyformat();
+    test_indentation();
+    test_getitemspacing();
+    test_getcolumnwidth();
+    test_approximate_viewrect();
+    test_finditem();
+    test_hover();
+    test_destroynotify();
+    test_createdragimage();
+
+    if (!load_v6_module(&ctx_cookie, &hCtx))
+    {
+        DestroyWindow(hwndparent);
+        return;
+    }
+
+    /* this is a XP SP3 failure workaround */
+    hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
+                           WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
+                           0, 0, 100, 100,
+                           hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+    if (!IsWindow(hwnd))
+    {
+        win_skip("FIXME: failed to create ListView window.\n");
+        unload_v6_module(ctx_cookie, hCtx);
+        DestroyWindow(hwndparent);
+        return;
+    }
+    else
+        DestroyWindow(hwnd);
+
+    /* comctl32 version 6 tests start here */
+    test_get_set_view();
+    test_canceleditlabel();
+    test_mapidindex();
+    test_scrollnotify();
+    test_LVS_EX_TRANSPARENTBKGND();
+    test_LVS_EX_HEADERINALLVIEWS();
+
+    unload_v6_module(ctx_cookie, hCtx);
+
+    DestroyWindow(hwndparent);
 }
 }
index e3cf04b..8f83260 100644 (file)
@@ -104,7 +104,9 @@ static void test_GetPtrAW(void)
         ok (count == sourcelen ||
             broken(count == 0), /* win9x */
             "Expected count to be %d, it was %d\n", sourcelen, count);
         ok (count == sourcelen ||
             broken(count == 0), /* win9x */
             "Expected count to be %d, it was %d\n", sourcelen, count);
-        ok (!lstrcmp(dest, desttest), "Expected destination to not have changed\n");
+        ok (!lstrcmp(dest, desttest) ||
+            broken(!lstrcmp(dest, "")), /* Win7 */
+            "Expected destination to not have changed\n");
 
         count = 0;
         count = pStr_GetPtrA(source, NULL, destsize);
 
         count = 0;
         count = pStr_GetPtrA(source, NULL, destsize);
index 1ca1997..30f682f 100644 (file)
 #include "msg.h"
 
 #define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got);
 #include "msg.h"
 
 #define expect(expected, got) ok(expected == got, "Expected %d, got %d\n", expected, got);
+#define expect_hex(expected, got) ok(expected == got, "Expected %x, got %x\n", expected, got);
 
 #define NUM_MSG_SEQUENCES   2
 #define PARENT_SEQ_INDEX    0
 #define MONTHCAL_SEQ_INDEX  1
 
 
 #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 struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
+static HWND parent_wnd;
+
 static const struct message create_parent_window_seq[] = {
     { WM_GETMINMAXINFO, sent },
     { WM_NCCREATE, sent },
 static const struct message create_parent_window_seq[] = {
     { WM_GETMINMAXINFO, sent },
     { WM_NCCREATE, sent },
@@ -56,7 +54,7 @@ static const struct message create_parent_window_seq[] = {
     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
     { WM_WINDOWPOSCHANGED, sent|optional },
     { WM_ACTIVATEAPP, sent|wparam, 1 },
     { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 },
     { WM_WINDOWPOSCHANGED, sent|optional },
     { WM_ACTIVATEAPP, sent|wparam, 1 },
-    { WM_NCACTIVATE, sent|wparam, 1 },
+    { WM_NCACTIVATE, sent },
     { WM_ACTIVATE, sent|wparam, 1 },
     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
     { WM_IME_NOTIFY, sent|defwinproc|optional },
     { WM_ACTIVATE, sent|wparam, 1 },
     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
     { WM_IME_NOTIFY, sent|defwinproc|optional },
@@ -81,6 +79,7 @@ static const struct message create_monthcal_multi_sel_style_seq[] = {
     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
     { WM_QUERYUISTATE, sent|optional },
     { WM_GETFONT, sent },
     { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
     { WM_QUERYUISTATE, sent|optional },
     { WM_GETFONT, sent },
+    { WM_PARENTNOTIFY, sent },
     { 0 }
 };
 
     { 0 }
 };
 
@@ -126,7 +125,6 @@ static const struct message monthcal_color_seq[] = {
 static const struct message monthcal_curr_date_seq[] = {
     { MCM_SETCURSEL, sent|wparam, 0},
     { WM_PAINT, sent|wparam|lparam|defwinproc, 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_SETCURSEL, sent|wparam, 0},
     { MCM_SETCURSEL, sent|wparam, 0},
     { MCM_GETCURSEL, sent|wparam, 0},
@@ -213,9 +211,6 @@ static const struct message monthcal_hit_test_seq[] = {
     { 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 }
 };
 
     { 0 }
 };
 
@@ -224,7 +219,7 @@ static const struct message monthcal_todaylink_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},
-    { WM_LBUTTONDOWN, sent|wparam|lparam, MK_LBUTTON, MAKELONG(70, 370)},
+    { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON},
     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0},
     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
     { MCM_GETCURSEL, sent|wparam, 0},
     { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0},
     { WM_PAINT, sent|wparam|lparam|defwinproc, 0, 0},
     { MCM_GETCURSEL, sent|wparam, 0},
@@ -289,6 +284,9 @@ static const struct message destroy_monthcal_child_msgs_seq[] = {
 
 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
     { 0x0090, sent|optional }, /* Vista */
 
 static const struct message destroy_monthcal_multi_sel_style_seq[] = {
     { 0x0090, sent|optional }, /* Vista */
+    { 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 }
     { WM_DESTROY, sent|wparam|lparam, 0, 0},
     { WM_NCDESTROY, sent|wparam|lparam, 0, 0},
     { 0 }
@@ -299,12 +297,14 @@ static const struct message destroy_parent_seq[] = {
     { 0x0090, sent|optional }, /* Vista */
     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
     { 0x0090, sent|optional }, /* Vista */
     { WM_WINDOWPOSCHANGING, sent|wparam, 0},
     { WM_WINDOWPOSCHANGED, sent|wparam, 0},
-    { WM_NCACTIVATE, sent|wparam, 0},
-    { WM_ACTIVATE, sent|wparam, 0},
+    { WM_IME_SETCONTEXT, sent|wparam|optional, 0},
+    { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
+    { WM_NCACTIVATE, sent|wparam|optional, 0},
+    { WM_ACTIVATE, sent|wparam|optional, 0},
     { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0},
     { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0},
     { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0},
     { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0},
-    { WM_ACTIVATEAPP, sent|wparam, 0},
-    { WM_KILLFOCUS, sent|wparam|lparam, 0, 0},
+    { WM_ACTIVATEAPP, sent|wparam|optional, 0},
+    { WM_KILLFOCUS, sent|wparam|lparam|optional, 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_IME_SETCONTEXT, sent|wparam|optional, 0},
     { WM_IME_NOTIFY, sent|wparam|lparam|defwinproc|optional, 1, 0},
     { WM_DESTROY, sent|wparam|lparam, 0, 0},
@@ -315,30 +315,97 @@ static const struct message destroy_parent_seq[] = {
 static void test_monthcal(void)
 {
     HWND hwnd;
 static void test_monthcal(void)
 {
     HWND hwnd;
-    SYSTEMTIME st[2], st1[2];
+    SYSTEMTIME st[2], st1[2], today;
     int res, month_range;
     int res, month_range;
+    DWORD limits;
 
     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
                          0, 300, 300, 0, 0, NULL, NULL);
     ok(hwnd != NULL, "Failed to create MonthCal\n");
 
     hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
                          0, 300, 300, 0, 0, NULL, NULL);
     ok(hwnd != NULL, "Failed to create MonthCal\n");
+
+    /* test range just after creation */
+    memset(&st, 0xcc, sizeof(st));
+    limits = SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st);
+    ok(limits == 0 ||
+       broken(limits == GDTR_MIN), /* comctl32 <= 4.70 */
+       "No limits should be set (%d)\n", limits);
+    if (limits == GDTR_MIN)
+    {
+        win_skip("comctl32 <= 4.70 is broken\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+
+    ok(0 == st[0].wYear ||
+       broken(1752 == st[0].wYear), /* comctl32 <= 4.72 */
+       "Expected 0, got %d\n", st[0].wYear);
+    ok(0 == st[0].wMonth ||
+       broken(9 == st[0].wMonth), /* comctl32 <= 4.72 */
+       "Expected 0, got %d\n", st[0].wMonth);
+    ok(0 == st[0].wDay ||
+       broken(14 == st[0].wDay), /* comctl32 <= 4.72 */
+       "Expected 0, got %d\n", st[0].wDay);
+    expect(0, st[0].wDayOfWeek);
+    expect(0, st[0].wHour);
+    expect(0, st[0].wMinute);
+    expect(0, st[0].wSecond);
+    expect(0, st[0].wMilliseconds);
+
+    expect(0, st[1].wYear);
+    expect(0, st[1].wMonth);
+    expect(0, st[1].wDay);
+    expect(0, st[1].wDayOfWeek);
+    expect(0, st[1].wHour);
+    expect(0, st[1].wMinute);
+    expect(0, st[1].wSecond);
+    expect(0, st[1].wMilliseconds);
+
     GetSystemTime(&st[0]);
     st[1] = st[0];
 
     GetSystemTime(&st[0]);
     st[1] = st[0];
 
+    SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&today);
+
     /* Invalid date/time */
     st[0].wYear  = 2000;
     /* Time should not matter */
     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
     /* Invalid date/time */
     st[0].wYear  = 2000;
     /* Time should not matter */
     st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
+    st[1].wMilliseconds = 1200;
     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
     ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
+    /* invalid timestamp is written back with today data and msecs untouched */
+    expect(today.wHour, st[1].wHour);
+    expect(today.wMinute, st[1].wMinute);
+    expect(today.wSecond, st[1].wSecond);
+    expect(1200, st[1].wMilliseconds);
+
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
-    ok(st1[0].wYear != 2000, "Lover limit changed\n");
+    ok(st1[0].wYear != 2000, "Lower limit changed\n");
+    /* invalid timestamp should be replaced with today data, except msecs */
+    expect(today.wHour, st1[1].wHour);
+    expect(today.wMinute, st1[1].wMinute);
+    expect(today.wSecond, st1[1].wSecond);
+    expect(1200, st1[1].wMilliseconds);
+
+    /* Invalid date/time with invalid milliseconds only */
+    GetSystemTime(&st[0]);
+    st[1] = st[0];
+    /* Time should not matter */
+    st[1].wMilliseconds = 1200;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
+    /* invalid milliseconds field doesn't lead to invalid timestamp */
+    expect(st[0].wHour,   st[1].wHour);
+    expect(st[0].wMinute, st[1].wMinute);
+    expect(st[0].wSecond, st[1].wSecond);
+    expect(1200, st[1].wMilliseconds);
+
+    GetSystemTime(&st[0]);
 
     st[1].wMonth = 0;
     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
 
     st[1].wMonth = 0;
     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
-    ok(st1[0].wYear != 2000, "Lover limit changed\n");
+    ok(st1[0].wYear != 2000, "Lower limit changed\n");
     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
     ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
     ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
-    ok(st1[0].wYear != 2000, "Lover limit changed\n");
+    ok(st1[0].wYear != 2000, "Lower limit changed\n");
 
     GetSystemTime(&st[0]);
     st[0].wDay = 20;
 
     GetSystemTime(&st[0]);
     st[0].wDay = 20;
@@ -373,6 +440,60 @@ static void test_monthcal(void)
     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");
 
     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");
 
+    /* set both limits, then set max < min */
+    GetSystemTime(&st[0]);
+    st[1] = st[0];
+    st[1].wYear++;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n");
+    st[1].wYear -= 2;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Max limit expected\n");
+
+    expect(0, st1[0].wYear);
+    expect(0, st1[0].wMonth);
+    expect(0, st1[0].wDay);
+    expect(0, st1[0].wDayOfWeek);
+    expect(0, st1[0].wHour);
+    expect(0, st1[0].wMinute);
+    expect(0, st1[0].wSecond);
+    expect(0, st1[0].wMilliseconds);
+
+    expect(st[1].wYear,      st1[1].wYear);
+    expect(st[1].wMonth,     st1[1].wMonth);
+    expect(st[1].wDay,       st1[1].wDay);
+    expect(st[1].wDayOfWeek, st1[1].wDayOfWeek);
+    expect(st[1].wHour,      st1[1].wHour);
+    expect(st[1].wMinute,    st1[1].wMinute);
+    expect(st[1].wSecond,    st1[1].wSecond);
+    expect(st[1].wMilliseconds, st1[1].wMilliseconds);
+
+    st[1] = st[0];
+    st[1].wYear++;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN|GDTR_MAX, (LPARAM)st), "Failed to set limits\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Min limit expected\n");
+    st[0].wYear++; /* start == end now */
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)st), "Failed to set limits\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MIN, "Min limit expected\n");
+
+    expect(st[0].wYear,      st1[0].wYear);
+    expect(st[0].wMonth,     st1[0].wMonth);
+    expect(st[0].wDay,       st1[0].wDay);
+    expect(st[0].wDayOfWeek, st1[0].wDayOfWeek);
+    expect(st[0].wHour,      st1[0].wHour);
+    expect(st[0].wMinute,    st1[0].wMinute);
+    expect(st[0].wSecond,    st1[0].wSecond);
+    expect(st[0].wMilliseconds, st1[0].wMilliseconds);
+
+    expect(0, st1[1].wYear);
+    expect(0, st1[1].wMonth);
+    expect(0, st1[1].wDay);
+    expect(0, st1[1].wDayOfWeek);
+    expect(0, st1[1].wHour);
+    expect(0, st1[1].wMinute);
+    expect(0, st1[1].wSecond);
+    expect(0, st1[1].wMilliseconds);
+
     DestroyWindow(hwnd);
 }
 
     DestroyWindow(hwnd);
 }
 
@@ -455,7 +576,7 @@ static HWND create_parent_window(void)
 
 static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -467,38 +588,40 @@ static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
     msg.lParam = lParam;
     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
 
     msg.lParam = lParam;
     add_message(sequences, MONTHCAL_SEQ_INDEX, &msg);
 
+    /* some debug output for style changing */
+    if ((message == WM_STYLECHANGING ||
+         message == WM_STYLECHANGED) && lParam)
+    {
+        STYLESTRUCT *style = (STYLESTRUCT*)lParam;
+        trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
+    }
+
     defwndproc_counter++;
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
 
     return ret;
 }
 
     defwndproc_counter--;
 
     return ret;
 }
 
-static HWND create_monthcal_control(DWORD style, HWND parent_window)
+static HWND create_monthcal_control(DWORD style)
 {
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND hwnd;
 
     HWND hwnd;
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
     hwnd = CreateWindowEx(0,
                     MONTHCAL_CLASS,
                     "",
     hwnd = CreateWindowEx(0,
                     MONTHCAL_CLASS,
                     "",
-                    style,
+                    WS_CHILD | WS_BORDER | WS_VISIBLE | style,
                     0, 0, 300, 400,
                     0, 0, 300, 400,
-                    parent_window, NULL, GetModuleHandleA(NULL), NULL);
+                    parent_wnd, NULL, GetModuleHandleA(NULL), NULL);
 
 
-    if (!hwnd)
-    {
-        HeapFree(GetProcessHeap(), 0, info);
-        return NULL;
-    }
+    if (!hwnd) return NULL;
+
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                        (LONG_PTR)monthcal_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
 
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
-                                            (LONG_PTR)monthcal_subclass_proc);
-    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+    SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
 
     return hwnd;
 }
 
     return hwnd;
 }
@@ -506,9 +629,12 @@ static HWND create_monthcal_control(DWORD style, HWND parent_window)
 
 /* Setter and Getters Tests */
 
 
 /* Setter and Getters Tests */
 
-static void test_monthcal_color(HWND hwnd)
+static void test_monthcal_color(void)
 {
     int res, temp;
 {
     int res, temp;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -574,12 +700,17 @@ static void test_monthcal_color(HWND hwnd)
     expect(RGB(255,255,255), temp);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
     expect(RGB(255,255,255), temp);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_color_seq, "monthcal color", FALSE);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_currDate(HWND hwnd)
+static void test_monthcal_currdate(void)
 {
     SYSTEMTIME st_original, st_new, st_test;
     int res;
 {
     SYSTEMTIME st_original, st_new, st_test;
     int res;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -629,28 +760,94 @@ static void test_monthcal_currDate(HWND hwnd)
     expect(st_original.wYear, st_new.wYear);
     expect(st_original.wMonth, st_new.wMonth);
     expect(st_original.wDay, st_new.wDay);
     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);
+    ok(st_original.wHour == st_new.wHour ||
+       broken(0 == st_new.wHour), /* comctl32 <= 4.70 */
+       "Expected %d, got %d\n", st_original.wHour, st_new.wHour);
+    ok(st_original.wMinute == st_new.wMinute ||
+       broken(0 == st_new.wMinute), /* comctl32 <= 4.70 */
+       "Expected %d, got %d\n", st_original.wMinute, st_new.wMinute);
+    ok(st_original.wSecond == st_new.wSecond ||
+       broken(0 == st_new.wSecond), /* comctl32 <= 4.70 */
+       "Expected %d, got %d\n", st_original.wSecond, st_new.wSecond);
 
     /* lparam cannot be NULL */
     res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0);
     expect(0, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
 
     /* lparam cannot be NULL */
     res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0);
     expect(0, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE);
+
+    /* December, 31, 9999 is the maximum allowed date */
+    memset(&st_new, 0, sizeof(st_new));
+    st_new.wYear = 9999;
+    st_new.wMonth = 12;
+    st_new.wDay = 31;
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
+    expect(1, res);
+    memset(&st_test, 0, sizeof(st_test));
+    res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_test);
+    expect(1, res);
+    expect(st_new.wYear, st_test.wYear);
+    expect(st_new.wMonth, st_test.wMonth);
+    expect(st_new.wDay, st_test.wDay);
+    expect(st_new.wHour, st_test.wHour);
+    expect(st_new.wMinute, st_test.wMinute);
+    expect(st_new.wSecond, st_test.wSecond);
+    /* try one day later */
+    st_original = st_new;
+    st_new.wYear = 10000;
+    st_new.wMonth = 1;
+    st_new.wDay = 1;
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
+    ok(0 == res ||
+       broken(1 == res), /* comctl32 <= 4.72 */
+       "Expected 0, got %d\n", res);
+    if (0 == res)
+    {
+        memset(&st_test, 0, sizeof(st_test));
+        res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_test);
+        expect(1, res);
+        expect(st_original.wYear, st_test.wYear);
+        expect(st_original.wMonth, st_test.wMonth);
+        expect(st_original.wDay, st_test.wDay);
+        expect(st_original.wHour, st_test.wHour);
+        expect(st_original.wMinute, st_test.wMinute);
+        expect(st_original.wSecond, st_test.wSecond);
+    }
+
+    /* setting selection equal to current reports success even if out range */
+    memset(&st_new, 0, sizeof(st_new));
+    st_new.wYear = 2009;
+    st_new.wDay  = 5;
+    st_new.wMonth = 10;
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
+    expect(1, res);
+    memset(&st_test, 0, sizeof(st_test));
+    st_test.wYear = 2009;
+    st_test.wDay  = 6;
+    st_test.wMonth = 10;
+    res = SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN, (LPARAM)&st_test);
+    expect(1, res);
+    /* set to current again */
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st_new);
+    expect(1, res);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_firstDay(HWND hwnd)
+static void test_monthcal_firstDay(void)
 {
     int res, fday, i, prev;
 {
     int res, fday, i, prev;
-    TCHAR b[128];
+    CHAR b[128];
     LCID lcid = LOCALE_USER_DEFAULT;
     LCID lcid = LOCALE_USER_DEFAULT;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Setter and Getters for first day of week */
     /* check for locale first day */
 
     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)){
+    if(GetLocaleInfoA(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){
         fday = atoi(b);
         trace("fday: %d\n", fday);
         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
         fday = atoi(b);
         trace("fday: %d\n", fday);
         res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
@@ -660,7 +857,7 @@ static void test_monthcal_firstDay(HWND hwnd)
         /* 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++){
         /* 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);
+            res = SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, i);
             expect(prev, res);
             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
             prev = res;
             expect(prev, res);
             res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0);
             prev = res;
@@ -681,11 +878,15 @@ static void test_monthcal_firstDay(HWND hwnd)
         skip("Cannot retrieve first day of the week\n");
     }
 
         skip("Cannot retrieve first day of the week\n");
     }
 
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_unicode(HWND hwnd)
+static void test_monthcal_unicode(void)
 {
     int res, temp;
 {
     int res, temp;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -700,11 +901,15 @@ static void test_monthcal_unicode(HWND hwnd)
 
     /* current setting is 1, so, should return 1 */
     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
 
     /* current setting is 1, so, should return 1 */
     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
-    todo_wine {expect(1, res);}
+    ok(1 == res ||
+       broken(0 == res), /* comctl32 <= 4.70 */
+       "Expected 1, got %d\n", res);
 
     /* setting to 0, should return previous settings */
     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
 
     /* setting to 0, should return previous settings */
     res = SendMessage(hwnd, MCM_SETUNICODEFORMAT, 0, 0);
-    todo_wine {expect(1, res);}
+    ok(1 == res ||
+       broken(0 == res), /* comctl32 <= 4.70 */
+       "Expected 1, got %d\n", res);
 
     /* current setting is 0, so, it should return 0 */
     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
 
     /* current setting is 0, so, it should return 0 */
     res = SendMessage(hwnd, MCM_GETUNICODEFORMAT, 0, 0);
@@ -715,22 +920,67 @@ static void test_monthcal_unicode(HWND hwnd)
     expect(0, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
     expect(0, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_unicode_seq, "monthcal unicode", FALSE);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_HitTest(HWND hwnd)
+static void test_monthcal_hittest(void)
 {
 {
+    typedef struct hittest_test
+    {
+       UINT ht;
+        int  todo;
+    } hittest_test_t;
+
+    static const hittest_test_t title_hits[] = {
+        /* Start is the same everywhere */
+        { MCHT_TITLE,        0 },
+        { MCHT_TITLEBTNPREV, 0 },
+        /* The middle piece is only tested for presence of items */
+        /* End is the same everywhere */
+        { MCHT_TITLEBTNNEXT, 0 },
+        { MCHT_TITLE,        0 },
+        { MCHT_NOWHERE,      1 }
+    };
+
     MCHITTESTINFO mchit;
     MCHITTESTINFO mchit;
-    UINT res;
+    UINT res, old_res;
     SYSTEMTIME st;
     LONG x;
     UINT title_index;
     SYSTEMTIME st;
     LONG x;
     UINT title_index;
-    static const UINT title_hits[] =
-        { MCHT_NOWHERE, MCHT_TITLEBK, MCHT_TITLEBTNPREV, MCHT_TITLEBK,
-          MCHT_TITLEMONTH, MCHT_TITLEBK, MCHT_TITLEYEAR, MCHT_TITLEBK,
-          MCHT_TITLEBTNNEXT, MCHT_TITLEBK, MCHT_NOWHERE };
+    HWND hwnd;
+    RECT r;
+    char yearmonth[80], *locale_month, *locale_year;
+    int month_count, year_count;
+    BOOL in_the_middle;
 
     memset(&mchit, 0, sizeof(MCHITTESTINFO));
 
 
     memset(&mchit, 0, sizeof(MCHITTESTINFO));
 
+    hwnd = create_monthcal_control(0);
+
+    /* test with invalid structure size */
+    mchit.cbSize = MCHITTESTINFO_V1_SIZE - 1;
+    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(-1, res);
+    expect(0, mchit.uHit);
+    /* test with invalid pointer */
+    res = SendMessage(hwnd, MCM_HITTEST, 0, 0);
+    expect(-1, res);
+
+    /* resize control to display single Calendar */
+    res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
+    if (res == 0)
+    {
+        win_skip("Message MCM_GETMINREQRECT unsupported. Skipping.\n");
+        DestroyWindow(hwnd);
+        return;
+    }
+    MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     st.wYear = 2007;
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     st.wYear = 2007;
@@ -745,60 +995,60 @@ static void test_monthcal_HitTest(HWND hwnd)
     res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
     expect(1,res);
 
     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);
+    /* (0, 0) is the top left of the control - title */
+    mchit.cbSize = MCHITTESTINFO_V1_SIZE;
     mchit.pt.x = 0;
     mchit.pt.y = 0;
     mchit.pt.x = 0;
     mchit.pt.y = 0;
-    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
     expect(0, mchit.pt.x);
     expect(0, mchit.pt.y);
     expect(mchit.uHit, res);
     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_hex(MCHT_TITLE, res);
+
+    /* bottom right of the control and should not be active */
+    mchit.pt.x = r.right;
+    mchit.pt.y = r.bottom;
+    res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
+    expect(r.right,  mchit.pt.x);
+    expect(r.bottom, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_NOWHERE, res);}
+    todo_wine expect_hex(MCHT_NOWHERE, res);
 
 
-    /* (500, 500) is completely out of the control and should not be active */
-    mchit.pt.x = 500;
-    mchit.pt.y = 500;
+    /* completely out of the control, should not be active */
+    mchit.pt.x = 2 * r.right;
+    mchit.pt.y = 2 * r.bottom;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(500, mchit.pt.x);
-    expect(500, mchit.pt.y);
+    expect(2 * r.right, mchit.pt.x);
+    expect(2 * r.bottom, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_NOWHERE, res);}
+    todo_wine expect_hex(MCHT_NOWHERE, res);
 
 
-    /* (120, 180) is in active area - calendar background */
-    mchit.pt.x = 120;
-    mchit.pt.y = 180;
+    /* in active area - day of the week */
+    mchit.pt.x = r.right / 2;
+    mchit.pt.y = r.bottom / 2;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(120, mchit.pt.x);
-    expect(180, mchit.pt.y);
+    expect(r.right / 2, mchit.pt.x);
+    expect(r.bottom / 2, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    expect(MCHT_CALENDARBK, res);
+    expect_hex(MCHT_CALENDARDATE, res);
 
 
-    /* (70, 70) is in active area - day of the week */
-    mchit.pt.x = 70;
-    mchit.pt.y = 70;
+    /* in active area - day of the week #2 */
+    mchit.pt.x = r.right / 14; /* half of first day rect */
+    mchit.pt.y = r.bottom / 2;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(70, mchit.pt.x);
-    expect(70, mchit.pt.y);
+    expect(r.right / 14, mchit.pt.x);
+    expect(r.bottom / 2, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_CALENDARDAY, res);}
+    expect_hex(MCHT_CALENDARDATE, res);
 
 
-    /* (70, 90) is in active area - date from prev month */
-    mchit.pt.x = 70;
-    mchit.pt.y = 90;
+    /* in active area - date from prev month */
+    mchit.pt.x = r.right / 14; /* half of first day rect */
+    mchit.pt.y = 6 * r.bottom / 19;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(70, mchit.pt.x);
-    expect(90, mchit.pt.y);
+    expect(r.right / 14, mchit.pt.x);
+    expect(6 * r.bottom / 19, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_CALENDARDATEPREV, res);}
+    expect_hex(MCHT_CALENDARDATEPREV, res);
 
 #if 0
     /* (125, 115) is in active area - date from this month */
 
 #if 0
     /* (125, 115) is in active area - date from this month */
@@ -811,142 +1061,164 @@ static void test_monthcal_HitTest(HWND hwnd)
     expect(MCHT_CALENDARDATE, res);
 #endif
 
     expect(MCHT_CALENDARDATE, res);
 #endif
 
-    /* (80, 220) is in active area - background section of the title */
-    mchit.pt.x = 80;
-    mchit.pt.y = 220;
+    /* in active area - date from next month */
+    mchit.pt.x = 11 * r.right / 14;
+    mchit.pt.y = 16 * r.bottom / 19;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(80, mchit.pt.x);
-    expect(220, mchit.pt.y);
+    expect(11 * r.right / 14, mchit.pt.x);
+    expect(16 * r.bottom / 19, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_TITLEBK, res);}
+    expect_hex(MCHT_CALENDARDATENEXT, res);
 
 
-    /* (140, 215) is in active area - month section of the title */
-    mchit.pt.x = 140;
-    mchit.pt.y = 215;
+    /* in active area - today link */
+    mchit.pt.x = r.right / 14;
+    mchit.pt.y = 18 * r.bottom / 19;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(140, mchit.pt.x);
-    expect(215, mchit.pt.y);
+    expect(r.right / 14, mchit.pt.x);
+    expect(18 * r.bottom / 19, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_TITLEMONTH, res);}
+    expect_hex(MCHT_TODAYLINK, res);
 
 
-    /* (170, 215) is in active area - year section of the title */
-    mchit.pt.x = 170;
-    mchit.pt.y = 215;
+    /* in active area - today link */
+    mchit.pt.x = r.right / 2;
+    mchit.pt.y = 18 * r.bottom / 19;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(170, mchit.pt.x);
-    expect(215, mchit.pt.y);
+    expect(r.right / 2, mchit.pt.x);
+    expect(18 * r.bottom / 19, mchit.pt.y);
     expect(mchit.uHit, res);
     expect(mchit.uHit, res);
-    todo_wine {expect(MCHT_TITLEYEAR, res);}
+    expect_hex(MCHT_TODAYLINK, res);
 
 
-    /* (150, 260) is in active area - date from this month */
-    mchit.pt.x = 150;
-    mchit.pt.y = 260;
+    /* in active area - today link */
+    mchit.pt.x = r.right / 10;
+    mchit.pt.y = 18 * r.bottom / 19;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(150, mchit.pt.x);
-    expect(260, mchit.pt.y);
+    expect(r.right / 10, mchit.pt.x);
+    expect(18 * r.bottom / 19, mchit.pt.y);
     expect(mchit.uHit, res);
     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);}
+    expect_hex(MCHT_TODAYLINK, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
 
     /* The horizontal position of title bar elements depends on locale (y pos
        is constant), so we sample across a horizontal line and make sure we
        find all elements. */
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE);
 
     /* The horizontal position of title bar elements depends on locale (y pos
        is constant), so we sample across a horizontal line and make sure we
        find all elements. */
-    mchit.pt.y = 40;
+
+    /* Get the format of the title */
+    GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SYEARMONTH, yearmonth, 80);
+    /* Find out if we have a month and/or year */
+    locale_year = strstr(yearmonth, "y");
+    locale_month = strstr(yearmonth, "M");
+
+    mchit.pt.x = 0;
+    mchit.pt.y = (5/2) * r.bottom / 19;
     title_index = 0;
     title_index = 0;
-    for (x = 0; x < 300; x++){
+    old_res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
+    expect_hex(title_hits[title_index].ht, old_res);
+
+    in_the_middle = FALSE;
+    month_count = year_count = 0;
+    for (x = 0; x < r.right; x++){
         mchit.pt.x = x;
         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
         expect(x, mchit.pt.x);
         mchit.pt.x = x;
         res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
         expect(x, mchit.pt.x);
-        expect(40, mchit.pt.y);
+        expect((5/2) * r.bottom / 19, mchit.pt.y);
         expect(mchit.uHit, res);
         expect(mchit.uHit, res);
-        if (res != title_hits[title_index]){
-            title_index++;
-            if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
-                break;
-            todo_wine {expect(title_hits[title_index], res);}
+        if (res != old_res) {
+
+            if (old_res == MCHT_TITLEBTNPREV)
+                in_the_middle = TRUE;
+
+            if (res == MCHT_TITLEBTNNEXT)
+                in_the_middle = FALSE;
+
+            if (in_the_middle) {
+                if (res == MCHT_TITLEMONTH)
+                    month_count++;
+                else if (res == MCHT_TITLEYEAR)
+                    year_count++;
+            } else {
+                title_index++;
+
+                if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
+                    break;
+
+                if (title_hits[title_index].todo) {
+                    todo_wine
+                    ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
+                                                          title_hits[title_index].ht, res, x);
+                } else {
+                    ok(title_hits[title_index].ht == res, "Expected %x, got %x, pos %d\n",
+                                                          title_hits[title_index].ht, res, x);
+                }
+            }
+            old_res = res;
         }
     }
         }
     }
-    todo_wine {ok(300 <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
-        "Wrong title layout\n");}
+
+    /* There are some limits, even if LOCALE_SYEARMONTH contains rubbish
+     * or no month/year indicators at all */
+    if (locale_month)
+        todo_wine ok(month_count == 1, "Expected 1 month item, got %d\n", month_count);
+    else
+        ok(month_count <= 1, "Too many month items: %d\n", month_count);
+
+    if (locale_year)
+        todo_wine ok(year_count == 1, "Expected 1 year item, got %d\n", year_count);
+    else
+        ok(year_count <= 1, "Too many year items: %d\n", year_count);
+
+    todo_wine ok(month_count + year_count >= 1, "Not enough month and year items\n");
+
+    ok(r.right <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
+       "Wrong title layout\n");
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_todaylink(HWND hwnd)
+static void test_monthcal_todaylink(void)
 {
     MCHITTESTINFO mchit;
     SYSTEMTIME st_test, st_new;
 {
     MCHITTESTINFO mchit;
     SYSTEMTIME st_test, st_new;
-    BOOL error = FALSE;
     UINT res;
     UINT res;
+    HWND hwnd;
+    RECT r;
 
     memset(&mchit, 0, sizeof(MCHITTESTINFO));
 
 
     memset(&mchit, 0, sizeof(MCHITTESTINFO));
 
+    hwnd = create_monthcal_control(0);
+
+    res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
+    MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     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;
+    /* hit active area - today link */
+    mchit.cbSize = MCHITTESTINFO_V1_SIZE;
+    mchit.pt.x = r.right / 14;
+    mchit.pt.y = 18 * r.bottom / 19;
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
     res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit);
-    expect(70, mchit.pt.x);
-    expect(370, mchit.pt.y);
+    expect(r.right / 14, mchit.pt.x);
+    expect(18 * r.bottom / 19, mchit.pt.y);
     expect(mchit.uHit, res);
     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;
+    expect(MCHT_TODAYLINK, res);
 
     st_test.wDay = 1;
     st_test.wMonth = 1;
     st_test.wYear = 2005;
 
     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);
 
 
     SendMessage(hwnd, MCM_SETTODAY, 0, (LPARAM)&st_test);
 
+    memset(&st_new, 0, sizeof(st_new));
     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);
     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));
+    res = SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(mchit.pt.x, mchit.pt.y));
     expect(0, res);
 
     expect(0, res);
 
-    memset(&st_new, 0, sizeof(SYSTEMTIME));
+    memset(&st_new, 0, sizeof(st_new));
     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
     expect(1, res);
     expect(1, st_new.wDay);
     res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM)&st_new);
     expect(1, res);
     expect(1, st_new.wDay);
@@ -954,18 +1226,24 @@ static void test_monthcal_todaylink(HWND hwnd)
     expect(2005, st_new.wYear);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
     expect(2005, st_new.wYear);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_todaylink_seq, "monthcal hit test", TRUE);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_today(HWND hwnd)
+static void test_monthcal_today(void)
 {
     SYSTEMTIME st_test, st_new;
     int res;
 {
     SYSTEMTIME st_test, st_new;
     int res;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Setter and Getters for "today" information */
 
     /* check for overflow, should be ok */
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Setter and Getters for "today" information */
 
     /* check for overflow, should be ok */
+    memset(&st_test, 0, sizeof(st_test));
     st_test.wDay = 38;
     st_test.wMonth = 38;
 
     st_test.wDay = 38;
     st_test.wMonth = 38;
 
@@ -1003,11 +1281,16 @@ static void test_monthcal_today(HWND hwnd)
     expect(0, st_new.wMonth);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
     expect(0, st_new.wMonth);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_today_seq, "monthcal today", TRUE);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_scroll(HWND hwnd)
+static void test_monthcal_scroll(void)
 {
     int res;
 {
     int res;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -1036,46 +1319,138 @@ static void test_monthcal_scroll(HWND hwnd)
     expect(-5, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
     expect(-5, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_scroll_seq, "monthcal scroll", FALSE);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_monthrange(HWND hwnd)
+static void test_monthcal_monthrange(void)
 {
     int res;
 {
     int res;
-    SYSTEMTIME st_visible[2], st_daystate[2];
+    SYSTEMTIME st_visible[2], st_daystate[2], st;
+    HWND hwnd;
+    RECT r;
+
+    hwnd = create_monthcal_control(0);
 
 
-    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];
 
     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];
 
+    st.wYear = 2000;
+    st.wMonth = 11;
+    st.wDay = 28;
+    st.wHour = 11;
+    st.wMinute = 59;
+    st.wSecond = 30;
+    st.wMilliseconds = 0;
+    st.wDayOfWeek = 0;
+
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
+    expect(1,res);
+
+    /* to be locale independent */
+    SendMessage(hwnd, MCM_SETFIRSTDAYOFWEEK, 0, (LPARAM)6);
+
+    res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r);
+    expect(TRUE, res);
+    /* resize control to display two Calendars */
+    MoveWindow(hwnd, 0, 0, r.right, (5/2)*r.bottom, FALSE);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
     todo_wine {
         expect(2, res);
     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(2000, st_visible[0].wYear);
+    expect(11, st_visible[0].wMonth);
+    expect(1, st_visible[0].wDay);
+    expect(2000, st_visible[1].wYear);
+
+    todo_wine {
         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(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(2000, st_daystate[0].wYear);
+    expect(10, st_daystate[0].wMonth);
+    expect(29, st_daystate[0].wDay);
+
+    todo_wine {
         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);
         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);
+
+    /* resize control to display single Calendar */
+    MoveWindow(hwnd, 0, 0, r.right, r.bottom, FALSE);
+
+    memset(&st, 0, sizeof(st));
+    st.wMonth = 9;
+    st.wYear  = 1752;
+    st.wDay   = 14;
+
+    res = SendMessage(hwnd, MCM_SETCURSEL, 0, (LPARAM)&st);
+    expect(1, res);
+
+    /* September 1752 has 19 days */
+    res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
+    expect(1, res);
+
+    expect(1752, st_visible[0].wYear);
+    expect(9, st_visible[0].wMonth);
+    ok(14 == st_visible[0].wDay ||
+       broken(1 == st_visible[0].wDay), /* comctl32 <= 4.72 */
+       "Expected 14, got %d\n", st_visible[0].wDay);
+
+    expect(1752, st_visible[1].wYear);
+    expect(9, st_visible[1].wMonth);
+    expect(19, st_visible[1].wDay);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_MaxSelDay(HWND hwnd)
+static void test_monthcal_maxselday(void)
 {
     int res;
 {
     int res;
+    HWND hwnd;
+    DWORD style;
+
+    hwnd = create_monthcal_control(0);
+    /* if no style specified default to 1 */
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    expect(1, res);
+    res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 5, 0);
+    expect(0, res);
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    expect(1, res);
+
+    /* try to set style */
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    SetWindowLong(hwnd, GWL_STYLE, style | MCS_MULTISELECT);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    ok(!(style & MCS_MULTISELECT), "Expected MCS_MULTISELECT not to be set\n");
+    DestroyWindow(hwnd);
+
+    hwnd = create_monthcal_control(MCS_MULTISELECT);
+    /* try to remove style */
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    SetWindowLong(hwnd, GWL_STYLE, style & ~MCS_MULTISELECT);
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    ok(style & MCS_MULTISELECT, "Expected MCS_MULTISELECT to be set\n");
+    DestroyWindow(hwnd);
+
+    hwnd = create_monthcal_control(MCS_MULTISELECT);
+
+    /* default width is a week */
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    expect(7, res);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -1090,20 +1465,32 @@ static void test_monthcal_MaxSelDay(HWND hwnd)
     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
     expect(15, res);
 
     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
     expect(15, res);
 
+    /* test invalid value */
     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
     res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
-    todo_wine {expect(0, res);}
+    expect(0, res);
     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
     res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
-    todo_wine {expect(15, res);}
+    expect(15, res);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE);
+
+    /* zero value is invalid too */
+    res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, 0, 0);
+    expect(0, res);
+    res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
+    expect(15, res);
+
+    DestroyWindow(hwnd);
 }
 
 }
 
-static void test_monthcal_size(HWND hwnd)
+static void test_monthcal_size(void)
 {
     int res;
     RECT r1, r2;
     HFONT hFont1, hFont2;
     LOGFONTA logfont;
 {
     int res;
     RECT r1, r2;
     HFONT hFont1, hFont2;
     LOGFONTA logfont;
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
 
     lstrcpyA(logfont.lfFaceName, "Arial");
     memset(&logfont, 0, sizeof(logfont));
 
     lstrcpyA(logfont.lfFaceName, "Arial");
     memset(&logfont, 0, sizeof(logfont));
@@ -1116,15 +1503,181 @@ static void test_monthcal_size(HWND hwnd)
     /* initialize to a font we can compare against */
     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
     /* initialize to a font we can compare against */
     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0);
     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1);
+    ok(res, "SendMessage(MCM_GETMINREQRECT) failed\n");
 
     /* check that setting a larger font results in an larger rect */
     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
 
     /* check that setting a larger font results in an larger rect */
     SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0);
     res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2);
+    ok(res, "SendMessage(MCM_GETMINREQRECT) failed\n");
 
     OffsetRect(&r1, -r1.left, -r1.top);
     OffsetRect(&r2, -r2.left, -r2.top);
 
     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
 
     OffsetRect(&r1, -r1.left, -r1.top);
     OffsetRect(&r2, -r2.left, -r2.top);
 
     ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n");
+
+    DestroyWindow(hwnd);
+}
+
+static void test_monthcal_create(void)
+{
+    HWND hwnd;
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    hwnd = create_monthcal_control(0);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_control_seq, "create monthcal control", TRUE);
+
+    DestroyWindow(hwnd);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    hwnd = create_monthcal_control(MCS_MULTISELECT);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, create_monthcal_multi_sel_style_seq, "create monthcal (multi sel style)", TRUE);
+    DestroyWindow(hwnd);
+}
+
+static void test_monthcal_destroy(void)
+{
+    HWND hwnd;
+
+    hwnd = create_monthcal_control(0);
+    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);
+
+    /* MCS_MULTISELECT */
+    hwnd = create_monthcal_control(MCS_MULTISELECT);
+    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);
+}
+
+static void test_monthcal_selrange(void)
+{
+    HWND hwnd;
+    SYSTEMTIME st, range[2], range2[2];
+    BOOL ret, old_comctl32 = FALSE;
+
+    hwnd = create_monthcal_control(MCS_MULTISELECT);
+
+    /* just after creation selection should start and end today */
+    ret = SendMessage(hwnd, MCM_GETTODAY, 0, (LPARAM)&st);
+    expect(TRUE, ret);
+
+    memset(range, 0xcc, sizeof(range));
+    ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range);
+    expect(TRUE, ret);
+    expect(st.wYear,      range[0].wYear);
+    expect(st.wMonth,     range[0].wMonth);
+    expect(st.wDay,       range[0].wDay);
+    if (range[0].wDayOfWeek != st.wDayOfWeek)
+    {
+        win_skip("comctl32 <= 4.70 doesn't set some values\n");
+        old_comctl32 = TRUE;
+    }
+    else
+    {
+        expect(st.wDayOfWeek, range[0].wDayOfWeek);
+        expect(st.wHour,      range[0].wHour);
+        expect(st.wMinute,    range[0].wMinute);
+        expect(st.wSecond,    range[0].wSecond);
+        expect(st.wMilliseconds, range[0].wMilliseconds);
+    }
+
+    expect(st.wYear,      range[1].wYear);
+    expect(st.wMonth,     range[1].wMonth);
+    expect(st.wDay,       range[1].wDay);
+    if (!old_comctl32)
+    {
+        expect(st.wDayOfWeek, range[1].wDayOfWeek);
+        expect(st.wHour,      range[1].wHour);
+        expect(st.wMinute,    range[1].wMinute);
+        expect(st.wSecond,    range[1].wSecond);
+        expect(st.wMilliseconds, range[1].wMilliseconds);
+    }
+
+    /* bounds are swapped if min > max */
+    memset(&range[0], 0, sizeof(range[0]));
+    range[0].wYear  = 2009;
+    range[0].wMonth = 10;
+    range[0].wDay   = 5;
+    range[1] = range[0];
+    range[1].wDay   = 3;
+
+    ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
+    expect(TRUE, ret);
+
+    ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
+    expect(TRUE, ret);
+
+    expect(range[1].wYear,      range2[0].wYear);
+    expect(range[1].wMonth,     range2[0].wMonth);
+    expect(range[1].wDay,       range2[0].wDay);
+    expect(6, range2[0].wDayOfWeek);
+    expect(range[1].wHour,      range2[0].wHour);
+    expect(range[1].wMinute,    range2[0].wMinute);
+    expect(range[1].wSecond,    range2[0].wSecond);
+    expect(range[1].wMilliseconds, range2[0].wMilliseconds);
+
+    expect(range[0].wYear,      range2[1].wYear);
+    expect(range[0].wMonth,     range2[1].wMonth);
+    expect(range[0].wDay,       range2[1].wDay);
+    expect(1, range2[1].wDayOfWeek);
+    expect(range[0].wHour,      range2[1].wHour);
+    expect(range[0].wMinute,    range2[1].wMinute);
+    expect(range[0].wSecond,    range2[1].wSecond);
+    expect(range[0].wMilliseconds, range2[1].wMilliseconds);
+
+    /* try with range larger than maximum configured */
+    memset(&range[0], 0, sizeof(range[0]));
+    range[0].wYear  = 2009;
+    range[0].wMonth = 10;
+    range[0].wDay   = 1;
+    range[1] = range[0];
+
+    ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
+    expect(TRUE, ret);
+
+    range[1] = range[0];
+    /* default max. range is 7 days */
+    range[1].wDay = 8;
+
+    ret = SendMessage(hwnd, MCM_SETSELRANGE, 0, (LPARAM)range);
+    expect(FALSE, ret);
+
+    ret = SendMessage(hwnd, MCM_GETSELRANGE, 0, (LPARAM)range2);
+    expect(TRUE, ret);
+
+    expect(range[0].wYear,  range2[0].wYear);
+    expect(range[0].wMonth, range2[0].wMonth);
+    expect(range[0].wDay,   range2[0].wDay);
+    expect(range[0].wYear,  range2[1].wYear);
+    expect(range[0].wMonth, range2[1].wMonth);
+    expect(range[0].wDay,   range2[1].wDay);
+
+    DestroyWindow(hwnd);
+}
+
+static void test_killfocus(void)
+{
+    HWND hwnd;
+    DWORD style;
+
+    hwnd = create_monthcal_control(0);
+
+    /* make parent invisible */
+    style = GetWindowLong(parent_wnd, GWL_STYLE);
+    SetWindowLong(parent_wnd, GWL_STYLE, style &~ WS_VISIBLE);
+
+    SendMessage(hwnd, WM_KILLFOCUS, (WPARAM)GetDesktopWindow(), 0);
+
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
+
+    style = GetWindowLong(parent_wnd, GWL_STYLE);
+    SetWindowLong(parent_wnd, GWL_STYLE, style | WS_VISIBLE);
+
+    DestroyWindow(hwnd);
 }
 
 START_TEST(monthcal)
 }
 
 START_TEST(monthcal)
@@ -1132,7 +1685,6 @@ START_TEST(monthcal)
     HMODULE hComctl32;
     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
     INITCOMMONCONTROLSEX iccex;
     HMODULE hComctl32;
     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
     INITCOMMONCONTROLSEX iccex;
-    HWND hwnd, parent_wnd;
 
     hComctl32 = GetModuleHandleA("comctl32.dll");
     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
 
     hComctl32 = GetModuleHandleA("comctl32.dll");
     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
@@ -1151,39 +1703,21 @@ START_TEST(monthcal)
 
     parent_wnd = create_parent_window();
 
 
     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);
-    test_monthcal_size(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);
+    test_monthcal_create();
+    test_monthcal_destroy();
+    test_monthcal_color();
+    test_monthcal_currdate();
+    test_monthcal_firstDay();
+    test_monthcal_unicode();
+    test_monthcal_today();
+    test_monthcal_scroll();
+    test_monthcal_monthrange();
+    test_monthcal_hittest();
+    test_monthcal_todaylink();
+    test_monthcal_size();
+    test_monthcal_maxselday();
+    test_monthcal_selrange();
+    test_killfocus();
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(parent_wnd);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     DestroyWindow(parent_wnd);
index 8ebec86..24fcff5 100644 (file)
@@ -69,11 +69,27 @@ static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA);
 static void   (WINAPI *pFreeMRUList)(HANDLE);
 static INT    (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
 static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
 static void   (WINAPI *pFreeMRUList)(HANDLE);
 static INT    (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
 static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
+static INT    (WINAPI *pEnumMRUListW)(HANDLE,INT,LPVOID,DWORD);
+static HANDLE (WINAPI *pCreateMRUListLazyA)(LPCREATEMRULISTA, DWORD, DWORD, DWORD);
+static INT    (WINAPI *pFindMRUData)(HANDLE, LPCVOID, DWORD, LPINT);
+static INT    (WINAPI *pAddMRUData)(HANDLE, LPCVOID, DWORD);
 /*
 static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
 */
 
 
 /*
 static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
 */
 
 
+static void InitPointers(void)
+{
+    pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
+    pFreeMRUList    = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
+    pAddMRUStringA  = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
+    pEnumMRUList    = (void*)GetProcAddress(hComctl32,(LPCSTR)154);
+    pCreateMRUListLazyA = (void*)GetProcAddress(hComctl32,(LPCSTR)157);
+    pAddMRUData     = (void*)GetProcAddress(hComctl32,(LPCSTR)167);
+    pFindMRUData    = (void*)GetProcAddress(hComctl32,(LPCSTR)169);
+    pEnumMRUListW   = (void*)GetProcAddress(hComctl32,(LPCSTR)403);
+}
+
 /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
 static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
 {
 /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */
 static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
 {
@@ -227,11 +243,6 @@ static void test_MRUListA(void)
     HKEY hKey;
     INT iRet;
 
     HKEY hKey;
     INT iRet;
 
-    pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
-    pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
-    pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
-    pEnumMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)154);
-
     if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUList)
     {
         skip("MRU entry points not found\n");
     if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUList)
     {
         skip("MRU entry points not found\n");
@@ -374,7 +385,7 @@ static void test_MRUListA(void)
         /* check entry 0 */
         buffer[0] = 0;
         iRet = pEnumMRUList(hMRU, 0, buffer, 255);
         /* check entry 0 */
         buffer[0] = 0;
         iRet = pEnumMRUList(hMRU, 0, buffer, 255);
-        todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
+        ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
         ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer);
 
         /* check entry 0 with a too small buffer */
         ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer);
 
         /* check entry 0 with a too small buffer */
@@ -383,21 +394,21 @@ static void test_MRUListA(void)
         buffer[2] = 'A'; /* unchanged */
         buffer[3] = 0;   /* unchanged */
         iRet = pEnumMRUList(hMRU, 0, buffer, 2);
         buffer[2] = 'A'; /* unchanged */
         buffer[3] = 0;   /* unchanged */
         iRet = pEnumMRUList(hMRU, 0, buffer, 2);
-        todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
-        todo_wine ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer);
+        ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
+        ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer);
         /* make sure space after buffer has old values */
         ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]);
 
         /* check entry 1 */
         buffer[0] = 0;
         iRet = pEnumMRUList(hMRU, 1, buffer, 255);
         /* make sure space after buffer has old values */
         ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]);
 
         /* check entry 1 */
         buffer[0] = 0;
         iRet = pEnumMRUList(hMRU, 1, buffer, 255);
-        todo_wine ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet);
+        ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet);
         ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer);
 
         /* check entry 2 */
         buffer[0] = 0;
         iRet = pEnumMRUList(hMRU, 2, buffer, 255);
         ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer);
 
         /* check entry 2 */
         buffer[0] = 0;
         iRet = pEnumMRUList(hMRU, 2, buffer, 255);
-        todo_wine ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet);
+        ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet);
         ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer);
 
         /* check out of bounds entry 3 */
         ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer);
 
         /* check out of bounds entry 3 */
@@ -413,6 +424,89 @@ static void test_MRUListA(void)
     /* FreeMRUList(NULL) crashes on Win98 OSR0 */
 }
 
     /* FreeMRUList(NULL) crashes on Win98 OSR0 */
 }
 
+static void test_CreateMRUListLazyA(void)
+{
+    HANDLE hMRU;
+    HKEY hKey;
+    CREATEMRULISTA listA = { 0 };
+
+    if (!pCreateMRUListLazyA || !pFreeMRUList)
+    {
+        win_skip("CreateMRUListLazyA or FreeMRUList entry points not found\n");
+        return;
+    }
+
+    /* wrong size */
+    listA.cbSize = sizeof(listA) + 1;
+    hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0);
+    ok(hMRU == NULL, "Expected NULL handle, got %p\n", hMRU);
+    listA.cbSize = 4;
+    hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0);
+    ok(hMRU == NULL, "Expected NULL handle, got %p\n", hMRU);
+    /* NULL hKey */
+    listA.cbSize = sizeof(listA);
+    listA.hKey = NULL;
+    hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0);
+    ok(hMRU == NULL, "Expected NULL handle, got %p\n", hMRU);
+    /* NULL subkey */
+    ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey),
+       "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
+    listA.cbSize = sizeof(listA);
+    listA.hKey = hKey;
+    listA.lpszSubKey = NULL;
+    hMRU = pCreateMRUListLazyA(&listA, 0, 0, 0);
+    ok(hMRU == NULL || broken(hMRU != NULL), /* Win9x */
+       "Expected NULL handle, got %p\n", hMRU);
+    if (hMRU) pFreeMRUList(hMRU);
+}
+
+static void test_EnumMRUList(void)
+{
+    if (!pEnumMRUList || !pEnumMRUListW)
+    {
+        win_skip("EnumMRUListA/EnumMRUListW entry point not found\n");
+        return;
+    }
+
+    /* NULL handle */
+    if (0)
+    {
+        /* crashes on NT4, passed on Win2k, XP, 2k3, Vista, 2k8 */
+        pEnumMRUList(NULL, 0, NULL, 0);
+        pEnumMRUListW(NULL, 0, NULL, 0);
+    }
+}
+
+static void test_FindMRUData(void)
+{
+    INT iRet;
+
+    if (!pFindMRUData)
+    {
+        win_skip("FindMRUData entry point not found\n");
+        return;
+    }
+
+    /* NULL handle */
+    iRet = pFindMRUData(NULL, NULL, 0, NULL);
+    ok(iRet == -1, "FindMRUData expected -1, got %d\n", iRet);
+}
+
+static void test_AddMRUData(void)
+{
+    INT iRet;
+
+    if (!pAddMRUData)
+    {
+        win_skip("AddMRUData entry point not found\n");
+        return;
+    }
+
+    /* NULL handle */
+    iRet = pFindMRUData(NULL, NULL, 0, NULL);
+    ok(iRet == -1, "AddMRUData expected -1, got %d\n", iRet);
+}
+
 START_TEST(mru)
 {
     hComctl32 = GetModuleHandleA("comctl32.dll");
 START_TEST(mru)
 {
     hComctl32 = GetModuleHandleA("comctl32.dll");
@@ -421,7 +515,13 @@ START_TEST(mru)
     if (!create_reg_entries())
         return;
 
     if (!create_reg_entries())
         return;
 
+    InitPointers();
+
     test_MRUListA();
     test_MRUListA();
+    test_CreateMRUListLazyA();
+    test_EnumMRUList();
+    test_FindMRUData();
+    test_AddMRUData();
 
     delete_reg_entries();
 }
 
     delete_reg_entries();
 }
diff --git a/rostests/winetests/comctl32/msg.c b/rostests/winetests/comctl32/msg.c
deleted file mode 100644 (file)
index 2129f22..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* 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)
-{
-}
index 2ec3ea1..361ccdb 100644 (file)
@@ -47,7 +47,8 @@ struct message
     msg_flags_t flags;  /* message props */
     WPARAM wParam;      /* expected value of wParam */
     LPARAM lParam;      /* expected value of lParam */
     msg_flags_t flags;  /* message props */
     WPARAM wParam;      /* expected value of wParam */
     LPARAM lParam;      /* expected value of lParam */
-    UINT id;            /* id of the window */
+    UINT id;            /* extra message data: id of the window,
+                           notify code etc. */
 };
 
 struct msg_sequence
 };
 
 struct msg_sequence
@@ -57,17 +58,237 @@ struct msg_sequence
     struct message *sequence;
 };
 
     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);
+static 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++;
+}
+
+static 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;
+}
+
+static void flush_sequences(struct msg_sequence **seq, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+        flush_sequence(seq, i);
+}
+
+static 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 && expected->flags & optional)
+                {
+                    expected++;
+                    continue;
+                }
+                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);
+}
 
 #define ok_sequence(seq, index, exp, contx, todo) \
         ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
 
 
 
 #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);
+static void init_msg_sequences(struct msg_sequence **seq, int n)
+{
+    int i;
 
 
-void init_msg_sequences(struct msg_sequence **seq, int n);
+    for (i = 0; i < n; i++)
+        seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct msg_sequence));
+}
index 10bbbef..3083e8b 100644 (file)
@@ -163,6 +163,7 @@ static void cleanup(void)
 static void test_redraw(void)
 {
     RECT client_rect;
 static void test_redraw(void)
 {
     RECT client_rect;
+    LRESULT ret;
 
     SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
     SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
 
     SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
     SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
@@ -184,7 +185,11 @@ static void test_redraw(void)
     /* 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");
     /* 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");
+    ret = SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0);
+    if (ret == 0)
+        win_skip("PBM_GETPOS needs comctl32 > 4.70\n");
+    else
+        ok(ret == 100, "PBM_GETPOS returned a wrong position : %d\n", (UINT)ret);
     
     /* PBM_SETRANGE and PBM_SETRANGE32:
     Usually the progress bar doesn't repaint itself immediately. If the
     
     /* PBM_SETRANGE and PBM_SETRANGE32:
     Usually the progress bar doesn't repaint itself immediately. If the
index 4164f68..bf40db4 100644 (file)
@@ -1,6 +1,7 @@
 /* Unit test suite for property sheet control.
  *
  * Copyright 2006 Huw Davies
 /* Unit test suite for property sheet control.
  *
  * Copyright 2006 Huw Davies
+ * Copyright 2009 Jan de Mooij
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <windows.h>
 #include <commctrl.h>
 
 #include <windows.h>
 #include <commctrl.h>
 
+#include "resources.h"
+
 #include "wine/test.h"
 
 static HWND parent;
 #include "wine/test.h"
 
 static HWND parent;
+static HWND sheethwnd;
+
+static LONG active_page = -1;
+
+#define IDC_APPLY_BUTTON 12321
 
 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
 {
 
 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
 {
@@ -33,12 +41,13 @@ static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
         char caption[256];
         GetWindowTextA(hwnd, caption, sizeof(caption));
         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
         char caption[256];
         GetWindowTextA(hwnd, caption, sizeof(caption));
         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
+        sheethwnd = hwnd;
         return 0;
       }
     }
     return 0;
 }
         return 0;
       }
     }
     return 0;
 }
-        
+
 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
                                       LPARAM lparam)
 {
 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
                                       LPARAM lparam)
 {
@@ -64,6 +73,10 @@ static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
             return FALSE;
         }
       }
             return FALSE;
         }
       }
+    case WM_NCDESTROY:
+        ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
+        return TRUE;
+
     default:
         return FALSE;
     }
     default:
         return FALSE;
     }
@@ -79,7 +92,7 @@ static void test_title(void)
     memset(&psp, 0, sizeof(psp));
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
     memset(&psp, 0, sizeof(psp));
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
-    psp.hInstance = GetModuleHandleW(NULL);
+    psp.hInstance = GetModuleHandleA(NULL);
     U(psp).pszTemplate = "prop_page1";
     U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = page_dlg_proc;
     U(psp).pszTemplate = "prop_page1";
     U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = page_dlg_proc;
@@ -97,6 +110,12 @@ static void test_title(void)
     psh.pfnCallback = sheet_callback;
 
     hdlg = (HWND)PropertySheetA(&psh);
     psh.pfnCallback = sheet_callback;
 
     hdlg = (HWND)PropertySheetA(&psh);
+    if (hdlg == INVALID_HANDLE_VALUE)
+    {
+        win_skip("comctl32 4.70 needs dwSize adjustment\n");
+        psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
+        hdlg = (HWND)PropertySheetA(&psh);
+    }
     DestroyWindow(hdlg);
 }
 
     DestroyWindow(hdlg);
 }
 
@@ -110,7 +129,7 @@ static void test_nopage(void)
     memset(&psp, 0, sizeof(psp));
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
     memset(&psp, 0, sizeof(psp));
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
-    psp.hInstance = GetModuleHandleW(NULL);
+    psp.hInstance = GetModuleHandleA(NULL);
     U(psp).pszTemplate = "prop_page1";
     U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = page_dlg_proc;
     U(psp).pszTemplate = "prop_page1";
     U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = page_dlg_proc;
@@ -128,6 +147,12 @@ static void test_nopage(void)
     psh.pfnCallback = sheet_callback;
 
     hdlg = (HWND)PropertySheetA(&psh);
     psh.pfnCallback = sheet_callback;
 
     hdlg = (HWND)PropertySheetA(&psh);
+    if (hdlg == INVALID_HANDLE_VALUE)
+    {
+        win_skip("comctl32 4.70 needs dwSize adjustment\n");
+        psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
+        hdlg = (HWND)PropertySheetA(&psh);
+    }
     ShowWindow(hdlg,SW_NORMAL);
     SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
     RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
     ShowWindow(hdlg,SW_NORMAL);
     SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
     RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
@@ -170,6 +195,7 @@ static void test_disableowner(void)
     HPROPSHEETPAGE hpsp[1];
     PROPSHEETPAGEA psp;
     PROPSHEETHEADERA psh;
     HPROPSHEETPAGE hpsp[1];
     PROPSHEETPAGEA psp;
     PROPSHEETHEADERA psh;
+    INT_PTR p;
 
     register_parent_wnd_class();
     parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
 
     register_parent_wnd_class();
     parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
@@ -177,7 +203,7 @@ static void test_disableowner(void)
     memset(&psp, 0, sizeof(psp));
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
     memset(&psp, 0, sizeof(psp));
     psp.dwSize = sizeof(psp);
     psp.dwFlags = 0;
-    psp.hInstance = GetModuleHandleW(NULL);
+    psp.hInstance = GetModuleHandleA(NULL);
     U(psp).pszTemplate = "prop_page1";
     U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = NULL;
     U(psp).pszTemplate = "prop_page1";
     U2(psp).pszIcon = NULL;
     psp.pfnDlgProc = NULL;
@@ -194,14 +220,227 @@ static void test_disableowner(void)
     U3(psh).phpage = hpsp;
     psh.pfnCallback = disableowner_callback;
 
     U3(psh).phpage = hpsp;
     psh.pfnCallback = disableowner_callback;
 
-    PropertySheetA(&psh);
+    p = PropertySheetA(&psh);
+    todo_wine
+    ok(p == 0, "Expected 0, got %ld\n", p);
     ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n");
     DestroyWindow(parent);
 }
 
     ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n");
     DestroyWindow(parent);
 }
 
+static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch(msg){
+    case WM_NOTIFY:
+        {
+            LPNMHDR hdr = (LPNMHDR)lparam;
+            switch(hdr->code){
+            case PSN_SETACTIVE:
+                active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd);
+                return TRUE;
+            case PSN_KILLACTIVE:
+                /* prevent navigation away from the fourth page */
+                if(active_page == 3){
+                    SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
+                    return TRUE;
+                }
+            }
+            break;
+        }
+    }
+    return FALSE;
+}
+
+static void test_wiznavigation(void)
+{
+    HPROPSHEETPAGE hpsp[4];
+    PROPSHEETPAGEA psp[4];
+    PROPSHEETHEADERA psh;
+    HWND hdlg, control;
+    LONG_PTR controlID;
+    LRESULT defidres;
+    BOOL hwndtoindex_supported = TRUE;
+    const INT nextID = 12324;
+    const INT backID = 12323;
+
+    /* create the property sheet pages */
+    memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
+
+    psp[0].dwSize = sizeof(PROPSHEETPAGEA);
+    psp[0].hInstance = GetModuleHandleA(NULL);
+    U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
+    psp[0].pfnDlgProc = nav_page_proc;
+    hpsp[0] = CreatePropertySheetPageA(&psp[0]);
+
+    psp[1].dwSize = sizeof(PROPSHEETPAGEA);
+    psp[1].hInstance = GetModuleHandleA(NULL);
+    U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
+    psp[1].pfnDlgProc = nav_page_proc;
+    hpsp[1] = CreatePropertySheetPageA(&psp[1]);
+
+    psp[2].dwSize = sizeof(PROPSHEETPAGEA);
+    psp[2].hInstance = GetModuleHandleA(NULL);
+    U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
+    psp[2].pfnDlgProc = nav_page_proc;
+    hpsp[2] = CreatePropertySheetPageA(&psp[2]);
+
+    psp[3].dwSize = sizeof(PROPSHEETPAGEA);
+    psp[3].hInstance = GetModuleHandleA(NULL);
+    U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
+    psp[3].pfnDlgProc = nav_page_proc;
+    hpsp[3] = CreatePropertySheetPageA(&psp[3]);
+
+    /* set up the property sheet dialog */
+    memset(&psh, 0, sizeof(psh));
+    psh.dwSize = sizeof(psh);
+    psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
+    psh.pszCaption = "A Wizard";
+    psh.nPages = 4;
+    psh.hwndParent = GetDesktopWindow();
+    U3(psh).phpage = hpsp;
+    hdlg = (HWND)PropertySheetA(&psh);
+    if (hdlg == INVALID_HANDLE_VALUE)
+    {
+        win_skip("comctl32 4.70 needs dwSize adjustment\n");
+        psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
+        hdlg = (HWND)PropertySheetA(&psh);
+    }
+
+    ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
+
+    control = GetFocus();
+    controlID = GetWindowLongPtr(control, GWLP_ID);
+    ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
+
+    /* simulate pressing the Next button */
+    SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
+    if (!active_page) hwndtoindex_supported = FALSE;
+    if (hwndtoindex_supported)
+        ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
+
+    control = GetFocus();
+    controlID = GetWindowLongPtr(control, GWLP_ID);
+    ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID);
+
+    defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
+    ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
+
+    /* set the focus to the second edit box on this page */
+    SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
+
+    /* press next again */
+    SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
+    if (hwndtoindex_supported)
+        ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
+
+    control = GetFocus();
+    controlID = GetWindowLongPtr(control, GWLP_ID);
+    ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
+
+    /* back button */
+    SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
+    if (hwndtoindex_supported)
+        ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
+
+    control = GetFocus();
+    controlID = GetWindowLongPtr(control, GWLP_ID);
+    ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID);
+
+    defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
+    ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
+
+    /* press next twice */
+    SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
+    if (hwndtoindex_supported)
+        ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
+    SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
+    if (hwndtoindex_supported)
+        ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
+    else
+        active_page = 3;
+
+    control = GetFocus();
+    controlID = GetWindowLongPtr(control, GWLP_ID);
+    ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
+
+    /* try to navigate away, but shouldn't be able to */
+    SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
+    ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
+
+    defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
+    ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
+
+    DestroyWindow(hdlg);
+}
+static void test_buttons(void)
+{
+    HPROPSHEETPAGE hpsp[1];
+    PROPSHEETPAGEA psp;
+    PROPSHEETHEADERA psh;
+    HWND hdlg;
+    HWND button;
+    RECT rc;
+    int prevRight, top;
+
+    memset(&psp, 0, sizeof(psp));
+    psp.dwSize = sizeof(psp);
+    psp.dwFlags = 0;
+    psp.hInstance = GetModuleHandleA(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);
+    if (hdlg == INVALID_HANDLE_VALUE)
+    {
+        win_skip("comctl32 4.70 needs dwSize adjustment\n");
+        psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
+        hdlg = (HWND)PropertySheetA(&psh);
+    }
+
+    /* OK button */
+    button = GetDlgItem(hdlg, IDOK);
+    GetWindowRect(button, &rc);
+    prevRight = rc.right;
+    top = rc.top;
+
+    /* Cancel button */
+    button = GetDlgItem(hdlg, IDCANCEL);
+    GetWindowRect(button, &rc);
+    ok(rc.top == top, "Cancel button should have same top as OK button\n");
+    ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
+    prevRight = rc.right;
+
+    button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
+    GetWindowRect(button, &rc);
+    ok(rc.top == top, "Apply button should have same top as OK button\n");
+    ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
+    prevRight = rc.right;
+
+    button = GetDlgItem(hdlg, IDHELP);
+    GetWindowRect(button, &rc);
+    ok(rc.top == top, "Help button should have same top as OK button\n");
+    ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
+
+    DestroyWindow(hdlg);
+}
+
 START_TEST(propsheet)
 {
     test_title();
     test_nopage();
     test_disableowner();
 START_TEST(propsheet)
 {
     test_title();
     test_nopage();
     test_disableowner();
+    test_wiznavigation();
+    test_buttons();
 }
 }
index d055d8a..a75a064 100644 (file)
@@ -32,7 +32,6 @@
 
 RECT height_change_notify_rect;
 static HWND hMainWnd;
 
 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 && \
 
 
 #define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \
@@ -66,14 +65,17 @@ static BOOL is_font_installed(const char *name)
     return ret;
 }
 
     return ret;
 }
 
-static void rebuild_rebar(HWND *hRebar)
+static HWND create_rebar_control(void)
 {
 {
-    if (*hRebar)
-        DestroyWindow(*hRebar);
+    HWND hwnd;
 
 
-    *hRebar = CreateWindow(REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
+    hwnd = CreateWindow(REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
         hMainWnd, (HMENU)17, GetModuleHandle(NULL), NULL);
         hMainWnd, (HMENU)17, GetModuleHandle(NULL), NULL);
-    SendMessageA(*hRebar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
+    ok(hwnd != NULL, "Failed to create Rebar\n");
+
+    SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0);
+
+    return hwnd;
 }
 
 static HWND build_toolbar(int nr, HWND hParent)
 }
 
 static HWND build_toolbar(int nr, HWND hParent)
@@ -85,7 +87,7 @@ static HWND build_toolbar(int nr, HWND hParent)
     int i;
 
     ok(hToolbar != NULL, "Toolbar creation problem\n");
     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_BUTTONSTRUCTSIZE, 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");
 
     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");
 
@@ -104,7 +106,7 @@ static HWND build_toolbar(int nr, HWND hParent)
         case 1: iBitmapId = IDB_VIEW_SMALL_COLOR; break;
         case 2: iBitmapId = IDB_STD_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_LOADIMAGES, iBitmapId, (LPARAM)HINST_COMMCTRL) == 0, "TB_LOADIMAGES failed\n");
     ok(SendMessage(hToolbar, TB_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n");
     return hToolbar;
 }
     ok(SendMessage(hToolbar, TB_ADDBUTTONS, 5+nr, (LPARAM)btns), "TB_ADDBUTTONS failed\n");
     return hToolbar;
 }
@@ -117,7 +119,7 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa
             {
                 NMHDR *lpnm = (NMHDR *)lParam;
                 if (lpnm->code == RBN_HEIGHTCHANGE)
             {
                 NMHDR *lpnm = (NMHDR *)lParam;
                 if (lpnm->code == RBN_HEIGHTCHANGE)
-                    GetClientRect(hRebar, &height_change_notify_rect);
+                    GetClientRect(lpnm->hwndFrom, &height_change_notify_rect);
             }
             break;
     }
             }
             break;
     }
@@ -150,7 +152,7 @@ static void dump_sizes(HWND hRebar)
     for (i=0; i<count; i++)
     {
         REBARBANDINFO rbi;
     for (i=0; i<count; i++)
     {
         REBARBANDINFO rbi;
-        rbi.cbSize = sizeof(REBARBANDINFO);
+        rbi.cbSize = REBARBANDINFOA_V6_SIZE;
         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");
         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");
@@ -310,10 +312,10 @@ static int rbsize_numtests = 0;
         count = SendMessage(hRebar, RB_GETBANDCOUNT, 0, 0); \
         compare(count, res->nBands, "%d"); \
         for (i=0; i<min(count, res->nBands); i++) { \
         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"); \
+            ok(SendMessageA(hRebar, RB_GETRECT, i, (LPARAM)&rc) == 1, "RB_GETRECT\n"); \
             if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \
                 check_rect("band", rc, res->bands[i].rc); \
             if (!(res->bands[i].fStyle & RBBS_HIDDEN)) \
                 check_rect("band", rc, res->bands[i].rc); \
-            rbi.cbSize = sizeof(REBARBANDINFO); \
+            rbi.cbSize = REBARBANDINFOA_V6_SIZE; \
             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"); \
             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"); \
@@ -329,11 +331,11 @@ static int rbsize_numtests = 0;
 static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal)
 {
     CHAR buffer[MAX_PATH];
 static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int cxIdeal)
 {
     CHAR buffer[MAX_PATH];
-    REBARBANDINFO rbi;
+    REBARBANDINFOA rbi;
 
     if (lpszText != NULL)
         strcpy(buffer, lpszText);
 
     if (lpszText != NULL)
         strcpy(buffer, lpszText);
-    rbi.cbSize = sizeof(rbi);
+    rbi.cbSize = REBARBANDINFOA_V6_SIZE;
     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT;
     rbi.cx = cx;
     rbi.cxMinChild = cxMinChild;
     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD | RBBIM_IDEALSIZE | RBBIM_TEXT;
     rbi.cx = cx;
     rbi.cxMinChild = cxMinChild;
@@ -344,16 +346,16 @@ static void add_band_w(HWND hRebar, LPCSTR lpszText, int cxMinChild, int cx, int
     SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
 }
 
     SendMessage(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
 }
 
-static void layout_test(void)
+static void test_layout(void)
 {
 {
-    HWND hRebar = NULL;
+    HWND hRebar;
     REBARBANDINFO rbi;
     HIMAGELIST himl;
     REBARINFO ri;
 
     REBARBANDINFO rbi;
     HIMAGELIST himl;
     REBARINFO ri;
 
-    rebuild_rebar(&hRebar);
+    hRebar = create_rebar_control();
     check_sizes();
     check_sizes();
-    rbi.cbSize = sizeof(rbi);
+    rbi.cbSize = REBARBANDINFOA_V6_SIZE;
     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
     rbi.cx = 200;
     rbi.cxMinChild = 100;
     rbi.fMask = RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_CHILD;
     rbi.cx = 200;
     rbi.cxMinChild = 100;
@@ -409,7 +411,9 @@ static void layout_test(void)
     SendMessageA(hRebar, RB_DELETEBAND, 1, 0);
     check_sizes();
 
     SendMessageA(hRebar, RB_DELETEBAND, 1, 0);
     check_sizes();
 
-    rebuild_rebar(&hRebar);
+    DestroyWindow(hRebar);
+
+    hRebar = create_rebar_control();
     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, "ABC",     70,  40, 100);
     add_band_w(hRebar, NULL,      40,  70, 100);
     add_band_w(hRebar, NULL,     170, 240, 100);
@@ -448,8 +452,10 @@ static void layout_test(void)
     SendMessage(hRebar, RB_SETBANDINFO, 1, (LPARAM)&rbi);
     check_sizes();
 
     SendMessage(hRebar, RB_SETBANDINFO, 1, (LPARAM)&rbi);
     check_sizes();
 
+    DestroyWindow(hRebar);
+
     /* VARHEIGHT resizing test on a horizontal rebar */
     /* VARHEIGHT resizing test on a horizontal rebar */
-    rebuild_rebar(&hRebar);
+    hRebar = create_rebar_control();
     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
     check_sizes();
     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
     check_sizes();
     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
@@ -474,8 +480,10 @@ static void layout_test(void)
     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
     check_sizes();
 
     SendMessageA(hRebar, RB_INSERTBAND, -1, (LPARAM)&rbi);
     check_sizes();
 
+    DestroyWindow(hRebar);
+
     /* VARHEIGHT resizing on a vertical rebar */
     /* VARHEIGHT resizing on a vertical rebar */
-    rebuild_rebar(&hRebar);
+    hRebar = create_rebar_control();
     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE);
     check_sizes();
     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
     SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | CCS_VERT | RBS_AUTOSIZE);
     check_sizes();
     rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
@@ -503,6 +511,7 @@ static void layout_test(void)
     check_sizes();
 
     DestroyWindow(hRebar);
     check_sizes();
 
     DestroyWindow(hRebar);
+    ImageList_Destroy(himl);
 }
 
 #if 0       /* use this to generate more tests */
 }
 
 #if 0       /* use this to generate more tests */
@@ -684,7 +693,7 @@ static int resize_numtests = 0;
 
 #endif
 
 
 #endif
 
-static void resize_test(void)
+static void test_resize(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,
 {
     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,
@@ -696,6 +705,8 @@ static void resize_test(void)
 
     for (i = 0; i < styles_count; i++)
     {
 
     for (i = 0; i < styles_count; i++)
     {
+        HWND hRebar;
+
         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);
         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);
@@ -735,17 +746,17 @@ static void resize_test(void)
     }
 }
 
     }
 }
 
-static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore,
+static void expect_band_content(HWND hRebar, 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,
     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)
+    INT cxHeader, INT cxHeader_broken)
 {
     CHAR buf[MAX_PATH] = "abc";
 {
     CHAR buf[MAX_PATH] = "abc";
-    REBARBANDINFO rb;
+    REBARBANDINFOA rb;
 
     memset(&rb, 0xdd, sizeof(rb));
 
     memset(&rb, 0xdd, sizeof(rb));
-    rb.cbSize = sizeof(rb);
+    rb.cbSize = REBARBANDINFOA_V6_SIZE;
     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.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;
@@ -753,8 +764,8 @@ static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore,
     rb.cch = MAX_PATH;
     ok(SendMessageA(hRebar, RB_GETBANDINFOA, uBand, (LPARAM)&rb), "RB_GETBANDINFO failed\n");
     expect_eq(rb.fStyle, fStyle, int, "%x");
     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(rb.clrFore, clrFore, COLORREF, "%x");
+    expect_eq(rb.clrBack, clrBack, COLORREF, "%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(strcmp(rb.lpText, lpText), 0, int, "%d");
     expect_eq(rb.iImage, iImage, int, "%x");
     expect_eq(rb.hwndChild, hwndChild, HWND, "%p");
@@ -769,20 +780,27 @@ static void expect_band_content(UINT uBand, INT fStyle, COLORREF clrFore,
     expect_eq(rb.cyIntegral, cyIntegral, int, "%x");
     expect_eq(rb.cxIdeal, cxIdeal, int, "%d");
     expect_eq(rb.lParam, lParam, LPARAM, "%ld");
     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");
+    ok( rb.cxHeader == cxHeader || broken(rb.cxHeader == cxHeader_broken),
+        "expected %d for %d\n", cxHeader, rb.cxHeader );
 }
 
 }
 
-static void bandinfo_test(void)
+static void test_bandinfo(void)
 {
     REBARBANDINFOA rb;
     CHAR szABC[] = "ABC";
     CHAR szABCD[] = "ABCD";
 {
     REBARBANDINFOA rb;
     CHAR szABC[] = "ABC";
     CHAR szABCD[] = "ABCD";
+    HWND hRebar;
 
 
-    rebuild_rebar(&hRebar);
-    rb.cbSize = sizeof(REBARBANDINFO);
+    hRebar = create_rebar_control();
+    rb.cbSize = REBARBANDINFOA_V6_SIZE;
     rb.fMask = 0;
     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);
+    if (!SendMessageA(hRebar, RB_INSERTBANDA, 0, (LPARAM)&rb))
+    {
+        win_skip( "V6 info not supported\n" );
+        DestroyWindow(hRebar);
+        return;
+    }
+    expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0, -1);
 
     rb.fMask = RBBIM_CHILDSIZE;
     rb.cxMinChild = 15;
 
     rb.fMask = RBBIM_CHILDSIZE;
     rb.cxMinChild = 15;
@@ -790,90 +808,157 @@ static void bandinfo_test(void)
     rb.cyChild = 30;
     rb.cyMaxChild = 20;
     rb.cyIntegral = 10;
     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);
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n");
+    expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 0, -1);
 
     rb.fMask = RBBIM_TEXT;
     rb.lpText = szABC;
 
     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);
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n");
+    expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 35, -1);
 
 
-    rb.cbSize = sizeof(REBARBANDINFO);
+    rb.cbSize = REBARBANDINFOA_V6_SIZE;
     rb.fMask = 0;
     ok(SendMessageA(hRebar, RB_INSERTBANDA, 1, (LPARAM)&rb), "RB_INSERTBAND failed\n");
     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);
+    expect_band_content(hRebar, 1, 0, 0, GetSysColor(COLOR_3DFACE), "", -1, NULL, 0, 0, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 9, -1);
+    expect_band_content(hRebar, 0, 0, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 40, -1);
 
     rb.fMask = RBBIM_HEADERSIZE;
     rb.cxHeader = 50;
 
     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);
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n");
+    expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 50, -1);
 
     rb.cxHeader = 5;
 
     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);
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n");
+    expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5, -1);
 
     rb.fMask = RBBIM_TEXT;
     rb.lpText = szABCD;
 
     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);
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n");
+    expect_band_content(hRebar, 0, 0x40000000, 0, GetSysColor(COLOR_3DFACE), "ABCD", -1, NULL, 15, 20, 0, NULL, 0, 0xdddddddd, 0xdddddddd, 0xdddddddd, 0, 0, 5, -1);
     rb.fMask = RBBIM_STYLE | RBBIM_TEXT;
     rb.fStyle = RBBS_VARIABLEHEIGHT;
     rb.lpText = szABC;
     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);
+    ok(SendMessageA(hRebar, RB_SETBANDINFOA, 0, (LPARAM)&rb), "RB_SETBANDINFO failed\n");
+    expect_band_content(hRebar, 0, RBBS_VARIABLEHEIGHT, 0, GetSysColor(COLOR_3DFACE), "ABC", -1, NULL, 15, 20, 0, NULL, 0, 20, 0x7fffffff, 0, 0, 0, 40, 5);
 
     DestroyWindow(hRebar);
 }
 
 
     DestroyWindow(hRebar);
 }
 
+static void test_colors(void)
+{
+    COLORSCHEME scheme;
+    COLORREF clr;
+    BOOL ret;
+    HWND hRebar;
+    REBARBANDINFOA bi;
+
+    hRebar = create_rebar_control();
+
+    /* test default colors */
+    clr = SendMessage(hRebar, RB_GETTEXTCOLOR, 0, 0);
+    compare(clr, CLR_NONE, "%x");
+    clr = SendMessage(hRebar, RB_GETBKCOLOR, 0, 0);
+    compare(clr, CLR_NONE, "%x");
+
+    scheme.dwSize = sizeof(scheme);
+    scheme.clrBtnHighlight = 0;
+    scheme.clrBtnShadow = 0;
+    ret = SendMessage(hRebar, RB_GETCOLORSCHEME, 0, (LPARAM)&scheme);
+    if (ret)
+    {
+        compare(scheme.clrBtnHighlight, CLR_DEFAULT, "%x");
+        compare(scheme.clrBtnShadow, CLR_DEFAULT, "%x");
+    }
+    else
+        skip("RB_GETCOLORSCHEME not supported\n");
+
+    /* check default band colors */
+    add_band_w(hRebar, "", 0, 10, 10);
+    bi.cbSize = REBARBANDINFOA_V6_SIZE;
+    bi.fMask = RBBIM_COLORS;
+    bi.clrFore = bi.clrBack = 0xc0ffe;
+    ret = SendMessage(hRebar, RB_GETBANDINFO, 0, (LPARAM)&bi);
+    ok(ret, "RB_GETBANDINFO failed\n");
+    compare(bi.clrFore, RGB(0, 0, 0), "%x");
+    compare(bi.clrBack, GetSysColor(COLOR_3DFACE), "%x");
+
+    SendMessage(hRebar, RB_SETTEXTCOLOR, 0, RGB(255, 0, 0));
+    bi.clrFore = bi.clrBack = 0xc0ffe;
+    ret = SendMessage(hRebar, RB_GETBANDINFO, 0, (LPARAM)&bi);
+    ok(ret, "RB_GETBANDINFO failed\n");
+    compare(bi.clrFore, RGB(0, 0, 0), "%x");
+
+    DestroyWindow(hRebar);
+}
+
+
+static BOOL register_parent_wnd_class(void)
+{
+    WNDCLASSA wc;
+
+    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;
+
+    return RegisterClassA(&wc);
+}
+
+static HWND create_parent_window(void)
+{
+    HWND hwnd;
+
+    if (!register_parent_wnd_class()) return NULL;
+
+    hwnd = 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);
+
+    ShowWindow(hwnd, SW_SHOW);
+    return hwnd;
+}
+
 START_TEST(rebar)
 {
     HMODULE hComctl32;
     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
     INITCOMMONCONTROLSEX iccex;
 START_TEST(rebar)
 {
     HMODULE hComctl32;
     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
     INITCOMMONCONTROLSEX iccex;
-    WNDCLASSA wc;
     MSG msg;
     MSG msg;
-    RECT rc;
 
     /* LoadLibrary is needed. This file has no references to functions in comctl32 */
     hComctl32 = LoadLibraryA("comctl32.dll");
     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
     if (!pInitCommonControlsEx)
     {
 
     /* LoadLibrary is needed. This file has no references to functions in comctl32 */
     hComctl32 = LoadLibraryA("comctl32.dll");
     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
     if (!pInitCommonControlsEx)
     {
-        skip("InitCommonControlsEx() is missing. Skipping the tests\n");
+        win_skip("InitCommonControlsEx() is missing. Skipping the tests\n");
         return;
     }
     iccex.dwSize = sizeof(iccex);
     iccex.dwICC = ICC_COOL_CLASSES;
     pInitCommonControlsEx(&iccex);
 
         return;
     }
     iccex.dwSize = sizeof(iccex);
     iccex.dwICC = ICC_COOL_CLASSES;
     pInitCommonControlsEx(&iccex);
 
-    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);
+    hMainWnd = create_parent_window();
 
 
-    bandinfo_test();
+    test_bandinfo();
+    test_colors();
 
 
-    if(is_font_installed("System") && is_font_installed("Tahoma"))
+    if(!is_font_installed("System") || !is_font_installed("Tahoma"))
     {
     {
-        layout_test();
-        resize_test();
-    } else
         skip("Missing System or Tahoma font\n");
         skip("Missing System or Tahoma font\n");
+        goto out;
+    }
+
+    test_layout();
+    test_resize();
 
 
+out:
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
         TranslateMessage(&msg);
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
         TranslateMessage(&msg);
index c99633d..8459fc8 100644 (file)
 #define IDS_TBADD5      20
 #define IDS_TBADD7      22
 
 #define IDS_TBADD5      20
 #define IDS_TBADD7      22
 
+#define IDD_PROP_PAGE_INTRO 30
+#define IDD_PROP_PAGE_EDIT 31
+#define IDD_PROP_PAGE_RADIO 32
+#define IDD_PROP_PAGE_EXIT 33
+
+#define IDC_PS_EDIT1 1000
+#define IDC_PS_EDIT2 1001
+#define IDC_PS_RADIO1 1010
+#define IDC_PS_RADIO2 1011
+
 #endif  /* __WINE_COMCTL32_TEST_RESOURCES_H */
 #endif  /* __WINE_COMCTL32_TEST_RESOURCES_H */
index bf195b6..06e382e 100644 (file)
@@ -30,6 +30,40 @@ FONT 8, "MS Shell Dlg"
  LTEXT "Test", -1, 10, 6, 100, 8
 }
 
  LTEXT "Test", -1, 10, 6, 100, 8
 }
 
+IDD_PROP_PAGE_INTRO DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CAPTION "Edit Control Page"
+FONT 8, "MS Shell Dlg"
+{
+    LTEXT "This is a test property sheet!", -1, 10, 6, 100, 8
+}
+
+IDD_PROP_PAGE_EDIT DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CAPTION "Edit Control Page"
+FONT 8, "MS Shell Dlg"
+{
+    EDITTEXT IDC_PS_EDIT1, 5, 5, 150, 140, WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE
+    EDITTEXT IDC_PS_EDIT2, 5, 160, 150, 28, WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE
+}
+
+IDD_PROP_PAGE_RADIO DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CAPTION "Edit Control Page"
+FONT 8, "MS Shell Dlg"
+{
+    CONTROL "Radio1", IDC_PS_RADIO1, "Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 20, 20, 39, 10
+    CONTROL "Radio2", IDC_PS_RADIO2, "Button", BS_AUTORADIOBUTTON, 20, 40, 39, 10
+}
+
+IDD_PROP_PAGE_EXIT DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CAPTION "Edit Control Page"
+FONT 8, "MS Shell Dlg"
+{
+    LTEXT "This has been a test property sheet!", -1, 10, 6, 170, 8
+}
+
 STRINGTABLE 
 {
     IDS_TBADD1           "abc"
 STRINGTABLE 
 {
     IDS_TBADD1           "abc"
index f1cbda4..839b138 100644 (file)
@@ -466,6 +466,112 @@ static void test_status_ownerdraw(void)
     SetWindowLongPtr( g_hMainWnd, GWLP_WNDPROC, (LONG_PTR)g_wndproc_saved );
 }
 
     SetWindowLongPtr( g_hMainWnd, GWLP_WNDPROC, (LONG_PTR)g_wndproc_saved );
 }
 
+static void test_gettext(void)
+{
+    HWND hwndStatus = CreateWindow(SUBCLASS_NAME, NULL, WS_CHILD|WS_VISIBLE,
+        0, 0, 300, 20, g_hMainWnd, NULL, NULL, NULL);
+    char buf[5];
+    int r;
+
+    r = SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)"Text");
+    expect(TRUE, r);
+    r = SendMessage(hwndStatus, WM_GETTEXTLENGTH, 0, 0);
+    expect(4, r);
+    /* A size of 0 returns the length of the text */
+    r = SendMessage(hwndStatus, WM_GETTEXT, 0, 0);
+    expect(4, r);
+    /* A size of 1 only stores the NULL terminator */
+    buf[0] = 0xa;
+    r = SendMessage(hwndStatus, WM_GETTEXT, 1, (LPARAM)buf);
+    ok( r == 0 || broken(r == 4), "Expected 0 got %d\n", r );
+    if (!r) ok(!buf[0], "expected empty buffer\n");
+    /* A size of 2 returns a length 1 */
+    r = SendMessage(hwndStatus, WM_GETTEXT, 2, (LPARAM)buf);
+    ok( r == 1 || broken(r == 4), "Expected 1 got %d\n", r );
+    r = SendMessage(hwndStatus, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
+    expect(4, r);
+    ok(!strcmp(buf, "Text"), "expected Text, got %s\n", buf);
+    DestroyWindow(hwndStatus);
+}
+
+/* Notify events to parent */
+static BOOL g_got_dblclk;
+static BOOL g_got_click;
+static BOOL g_got_rdblclk;
+static BOOL g_got_rclick;
+
+/* Messages to parent */
+static BOOL g_got_contextmenu;
+
+static LRESULT WINAPI test_notify_parent_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+   switch(msg)
+   {
+       case WM_NOTIFY:
+       {
+           NMHDR *hdr = ((LPNMHDR)lParam);
+           switch(hdr->code)
+           {
+               case NM_DBLCLK: g_got_dblclk = TRUE; break;
+               case NM_CLICK: g_got_click = TRUE; break;
+               case NM_RDBLCLK: g_got_rdblclk = TRUE; break;
+               case NM_RCLICK: g_got_rclick = TRUE; break;
+           }
+
+           /* Return zero to indicate default processing */
+           return 0;
+       }
+
+       case WM_CONTEXTMENU: g_got_contextmenu = TRUE; return 0;
+
+       default:
+            return( DefWindowProcA(hwnd, msg, wParam, lParam));
+   }
+
+   return 0;
+}
+
+/* Test that WM_NOTIFY messages from the status control works correctly */
+static void test_notify(void)
+{
+    HWND hwndParent;
+    HWND hwndStatus;
+    ATOM atom;
+    WNDCLASSA wclass = {0};
+    wclass.lpszClassName = "TestNotifyParentClass";
+    wclass.lpfnWndProc   = test_notify_parent_proc;
+    atom = RegisterClassA(&wclass);
+    ok(atom, "RegisterClass failed\n");
+
+    /* create parent */
+    hwndParent = CreateWindow(wclass.lpszClassName, "parent", WS_OVERLAPPEDWINDOW,
+      CW_USEDEFAULT, 0, 300, 20, NULL, NULL, NULL, NULL);
+    ok(hwndParent != NULL, "Parent creation failed!\n");
+
+    /* create status bar */
+    hwndStatus = CreateWindow(STATUSCLASSNAME, NULL, WS_VISIBLE | WS_CHILD,
+      0, 0, 300, 20, hwndParent, NULL, NULL, NULL);
+    ok(hwndStatus != NULL, "Status creation failed!\n");
+
+    /* Send various mouse event, and check that we get them */
+    g_got_dblclk = FALSE;
+    SendMessage(hwndStatus, WM_LBUTTONDBLCLK, 0, 0);
+    ok(g_got_dblclk, "WM_LBUTTONDBLCLK was not processed correctly!\n");
+    g_got_rdblclk = FALSE;
+    SendMessage(hwndStatus, WM_RBUTTONDBLCLK, 0, 0);
+    ok(g_got_rdblclk, "WM_RBUTTONDBLCLK was not processed correctly!\n");
+    g_got_click = FALSE;
+    SendMessage(hwndStatus, WM_LBUTTONUP, 0, 0);
+    ok(g_got_click, "WM_LBUTTONUP was not processed correctly!\n");
+
+    /* For R-UP, check that we also get the context menu from the default processing */
+    g_got_contextmenu = FALSE;
+    g_got_rclick = FALSE;
+    SendMessage(hwndStatus, WM_RBUTTONUP, 0, 0);
+    ok(g_got_rclick, "WM_RBUTTONUP was not processed correctly!\n");
+    ok(g_got_contextmenu, "WM_RBUTTONUP did not activate the context menu!\n");
+}
+
 START_TEST(status)
 {
     hinst = GetModuleHandleA(NULL);
 START_TEST(status)
 {
     hinst = GetModuleHandleA(NULL);
@@ -483,4 +589,6 @@ START_TEST(status)
     test_create();
     test_height();
     test_status_ownerdraw();
     test_create();
     test_height();
     test_status_ownerdraw();
+    test_gettext();
+    test_notify();
 }
 }
index f4d0b72..8511275 100644 (file)
@@ -279,21 +279,49 @@ static BOOL RegisterWindowClasses(void)
     return TRUE;
 }
 
     return TRUE;
 }
 
-START_TEST(subclass)
+static int init_function_pointers(void)
 {
 {
-    HMODULE hdll;
-    
-    hdll = GetModuleHandleA("comctl32.dll");
-    assert(hdll);
+    HMODULE hmod;
+    void *ptr;
+
+    hmod = GetModuleHandleA("comctl32.dll");
+    assert(hmod);
+
     /* Functions have to be loaded by ordinal. Only XP and W2K3 export
      * them by name.
      */
     /* 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);
-    
+#define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
+    MAKEFUNC_ORD(SetWindowSubclass, 410);
+    MAKEFUNC_ORD(RemoveWindowSubclass, 412);
+    MAKEFUNC_ORD(DefSubclassProc, 413);
+#undef MAKEFUNC_ORD
+
     if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc)
     if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc)
-        return;
+    {
+        win_skip("SetWindowSubclass and friends are not available\n");
+        return 0;
+    }
+
+    /* test named exports */
+    ptr = GetProcAddress(hmod, "SetWindowSubclass");
+    ok(broken(ptr == 0) || ptr != 0, "expected named export for SetWindowSubclass\n");
+    if(ptr)
+    {
+#define TESTNAMED(f) \
+    ptr = (void*)GetProcAddress(hmod, #f); \
+    ok(ptr != 0, "expected named export for " #f "\n");
+        TESTNAMED(RemoveWindowSubclass);
+        TESTNAMED(DefSubclassProc);
+        /* GetWindowSubclass exported for V6 only */
+#undef TESTNAMED
+    }
+
+    return 1;
+}
+
+START_TEST(subclass)
+{
+    if(!init_function_pointers()) return;
 
     if(!RegisterWindowClasses()) assert(0);
 
 
     if(!RegisterWindowClasses()) assert(0);
 
index 3bf6894..6774d51 100644 (file)
@@ -89,13 +89,14 @@ static const struct message create_parent_wnd_seq[] = {
 
 static const struct message add_tab_to_parent[] = {
     { TCM_INSERTITEMA, sent },
 
 static const struct message add_tab_to_parent[] = {
     { TCM_INSERTITEMA, sent },
-    { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent|optional },
     { WM_NOTIFYFORMAT, sent|defwinproc },
     { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc|optional, 0, 0 },
     { WM_PARENTNOTIFY, sent|defwinproc },
     { TCM_INSERTITEMA, sent },
     { TCM_INSERTITEMA, sent },
     { TCM_INSERTITEMA, sent },
     { WM_NOTIFYFORMAT, sent|defwinproc },
     { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc|optional, 0, 0 },
     { WM_PARENTNOTIFY, sent|defwinproc },
     { TCM_INSERTITEMA, sent },
     { TCM_INSERTITEMA, sent },
     { TCM_INSERTITEMA, sent },
+    { TCM_INSERTITEMA, sent|optional },
     { 0 }
 };
 
     { 0 }
 };
 
@@ -236,12 +237,15 @@ 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, 1 },
+    { WM_NOTIFYFORMAT, sent|defwinproc|optional },
+    { WM_QUERYUISTATE, sent|defwinproc|optional },
+    { WM_PARENTNOTIFY, sent|defwinproc|optional },
     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
     { TCM_INSERTITEM, sent|wparam, 2 },
     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
     { TCM_INSERTITEM, sent|wparam, 2 },
-    { WM_NOTIFYFORMAT, sent|defwinproc, },
+    { WM_NOTIFYFORMAT, sent|defwinproc|optional },
     { WM_QUERYUISTATE, sent|defwinproc|optional, },
     { WM_QUERYUISTATE, sent|defwinproc|optional, },
-    { WM_PARENTNOTIFY, sent|defwinproc, },
+    { WM_PARENTNOTIFY, sent|defwinproc|optional },
     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
     { TCM_SETCURFOCUS, 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 },
@@ -370,14 +374,9 @@ static HWND createParentWindow(void)
                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
 }
 
                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
 }
 
-struct subclass_info
-{
-    WNDPROC oldproc;
-};
-
 static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-    struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -402,7 +401,7 @@ static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam,
     }
 
     defwndproc_counter++;
     }
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
 
     return ret;
     defwndproc_counter--;
 
     return ret;
@@ -412,14 +411,10 @@ static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT
 {
     HWND tabHandle;
     TCITEM tcNewTab;
 {
     HWND tabHandle;
     TCITEM tcNewTab;
-    struct subclass_info *info;
+    WNDPROC oldproc;
     RECT rect;
     INT i;
 
     RECT rect;
     INT i;
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
     GetClientRect(parent_wnd, &rect);
 
     tabHandle = CreateWindow (
     GetClientRect(parent_wnd, &rect);
 
     tabHandle = CreateWindow (
@@ -431,8 +426,8 @@ static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT
 
     assert(tabHandle);
 
 
     assert(tabHandle);
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess);
-    SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess);
+    SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     tcNewTab.mask = mask;
 
 
     tcNewTab.mask = mask;
 
@@ -505,7 +500,7 @@ static void test_tab(INT nMinTabWidth)
     SIZE size;
     HDC hdc;
     HFONT hOldFont;
     SIZE size;
     HDC hdc;
     HFONT hOldFont;
-    INT i, dpi;
+    INT i, dpi, exp;
 
     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
 
     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
@@ -585,8 +580,11 @@ static void test_tab(INT nMinTabWidth)
     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
 
     trace ("  non fixed width, with text...\n");
     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
 
     trace ("  non fixed width, with text...\n");
-    CheckSize(hwTab, max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth), -1,
-              "no icon, default width");
+    exp = max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth);
+    SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
+    ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
+        "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
+
     for (i=0; i<8; i++)
     {
         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
     for (i=0; i<8; i++)
     {
         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
@@ -610,7 +608,11 @@ static void test_tab(INT nMinTabWidth)
     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
 
     trace ("  non fixed width, no text...\n");
     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
 
     trace ("  non fixed width, no text...\n");
-    CheckSize(hwTab, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth, -1, "no icon, default width");
+    exp = (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth;
+    SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
+    ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
+        "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
+
     for (i=0; i<8; i++)
     {
         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
     for (i=0; i<8; i++)
     {
         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
@@ -636,220 +638,246 @@ static void test_tab(INT nMinTabWidth)
     DeleteObject(hFont);
 }
 
     DeleteObject(hFont);
 }
 
-static void test_getters_setters(HWND parent_wnd, INT nTabs)
+static void test_curfocus(HWND parent_wnd, INT nTabs)
 {
 {
+    INT focusIndex;
     HWND hTab;
     HWND hTab;
-    RECT rTab;
-    INT nTabsRetrieved;
-    INT rowCount;
-    INT dpi;
-    HDC hdc;
-
-    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");
 
 
     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);
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
-    ok(SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1) > 0,"TCM_SETMINTABWIDTH returned < 0\n");
-    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 CurFocus with largest appropriate value */
+    SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0);
+    focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(nTabs-1, focusIndex);
 
 
-    /* Testing GetItemRect */
-    flush_sequences(sequences, NUM_MSG_SEQUENCES);
-    ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n");
+    /* Testing CurFocus with negative value */
+    SendMessage(hTab, TCM_SETCURFOCUS, -10, 0);
+    focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(-1, focusIndex);
 
 
-    hdc = GetDC(hTab);
-    dpi = GetDeviceCaps(hdc, LOGPIXELSX);
-    ReleaseDC(hTab, hdc);
-    CheckSize(hTab, dpi, -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 with value larger than number of tabs */
+    focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
+    expect(-1, focusIndex);
 
 
-    /* Testing CurFocus */
-    {
-        INT focusIndex;
+    SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0);
+    focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
+    expect(1, focusIndex);
 
 
-        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE);
 
 
-        /* Testing CurFocus with largest appropriate value */
-        SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0);
-        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
-            expect(nTabs-1, focusIndex);
+    DestroyWindow(hTab);
+}
 
 
-        /* Testing CurFocus with negative value */
-        SendMessage(hTab, TCM_SETCURFOCUS, -10, 0);
-        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
-            expect(-1, focusIndex);
+static void test_cursel(HWND parent_wnd, INT nTabs)
+{
+    INT selectionIndex;
+    INT focusIndex;
+    TCITEM tcItem;
+    HWND hTab;
 
 
-        /* Testing CurFocus with value larger than number of tabs */
-        focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
-        todo_wine{
-            expect(-1, focusIndex);
-        }
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
+    ok(hTab != NULL, "Failed to create tab control\n");
 
 
-        SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0);
-        focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
-            expect(1, focusIndex);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
-        ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE);
-    }
+    /* Testing CurSel with largest appropriate value */
+    selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0);
+    expect(0, 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);
+
+    /* selected item should have TCIS_BUTTONPRESSED state
+       It doesn't depend on button state */
+    memset(&tcItem, 0, sizeof(TCITEM));
+    tcItem.mask = TCIF_STATE;
+    tcItem.dwStateMask = TCIS_BUTTONPRESSED;
+    selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
+    SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem);
+    ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */
+        "Selected item should have TCIS_BUTTONPRESSED\n");
 
 
-    /* Testing CurSel */
-    {
-        INT selectionIndex;
-        INT focusIndex;
-        TCITEM tcItem;
-
-        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);
-
-        /* selected item should have TCIS_BUTTONPRESSED state
-           It doesn't depend on button state */
-        memset(&tcItem, 0, sizeof(TCITEM));
-        tcItem.mask = TCIF_STATE;
-        tcItem.dwStateMask = TCIS_BUTTONPRESSED;
-        selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
-        SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem);
-        ok (tcItem.dwState & TCIS_BUTTONPRESSED, "Selected item should have TCIS_BUTTONPRESSED\n");
-    }
+    DestroyWindow(hTab);
+}
 
 
-    /* Testing ExtendedStyle */
-    {
-        DWORD prevExtendedStyle;
-        DWORD extendedStyle;
+static void test_extendedstyle(HWND parent_wnd, INT nTabs)
+{
+    DWORD prevExtendedStyle;
+    DWORD extendedStyle;
+    HWND hTab;
 
 
-        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");
 
 
-        /* Testing Flat Separators */
-        extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
-        prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
-        expect(extendedStyle, prevExtendedStyle);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
-        extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
-        expect(TCS_EX_FLATSEPARATORS, extendedStyle);
+    /* Testing Flat Separators */
+    extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
+    prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
+    expect(extendedStyle, prevExtendedStyle);
 
 
-        /* Testing Register Drop */
-        prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
-            expect(extendedStyle, prevExtendedStyle);
+    extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
+    expect(TCS_EX_FLATSEPARATORS, extendedStyle);
 
 
-        extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
-        todo_wine{
-            expect(TCS_EX_REGISTERDROP, extendedStyle);
-        }
+    /* Testing Register Drop */
+    prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
+    expect(extendedStyle, prevExtendedStyle);
 
 
-        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);
+    extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
+    todo_wine{
+        expect(TCS_EX_REGISTERDROP, extendedStyle);
     }
 
     }
 
-    /* Testing UnicodeFormat */
-    {
-        INT unicodeFormat;
+    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);
 
 
-        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    DestroyWindow(hTab);
+}
 
 
-        unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
-        todo_wine{
-            expect(0, unicodeFormat);
-        }
-        unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
-            expect(1, unicodeFormat);
+static void test_unicodeformat(HWND parent_wnd, INT nTabs)
+{
+    INT unicodeFormat;
+    HWND hTab;
 
 
-        unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
-            expect(1, unicodeFormat);
-        unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
-            expect(0, unicodeFormat);
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
+    ok(hTab != NULL, "Failed to create tab control\n");
 
 
-        unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
-            expect(0, unicodeFormat);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
-        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);
+    unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
+    todo_wine{
+        expect(0, unicodeFormat);
     }
     }
+    unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
+    expect(1, unicodeFormat);
 
 
-    /* Testing GetSet Item */
-    {
-        TCITEM tcItem;
-        char szText[32] = "New Label";
+    unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
+    expect(1, unicodeFormat);
+    unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
+    expect(0, unicodeFormat);
 
 
-        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
+    expect(0, unicodeFormat);
 
 
-        tcItem.mask = TCIF_TEXT;
-        tcItem.pszText = &szText[0];
-        tcItem.cchTextMax = sizeof(szText);
+    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);
 
 
-        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);
+    DestroyWindow(hTab);
+}
+
+static void test_getset_item(HWND parent_wnd, INT nTabs)
+{
+    TCITEM tcItem;
+    DWORD ret;
+    char szText[32] = "New Label";
+    HWND hTab;
 
 
-        ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n");
-        expect_str("Tab 2", tcItem.pszText);
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
+    ok(hTab != NULL, "Failed to create tab control\n");
 
 
-        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);
+    /* passing invalid index should result in initialization to zero
+       for members mentioned in mask requested */
+
+    /* valid range here is [0,4] */
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_PARAM;
+    ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
+
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_IMAGE;
+    ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    expect(0, tcItem.iImage);
+
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_TEXT;
+    tcItem.pszText = szText;
+    szText[0] = 'a';
+    ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    expect('a', szText[0]);
+
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_STATE;
+    tcItem.dwStateMask = 0;
+    tcItem.dwState = TCIS_BUTTONPRESSED;
+    ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState);
+
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_STATE;
+    tcItem.dwStateMask = TCIS_BUTTONPRESSED;
+    tcItem.dwState = TCIS_BUTTONPRESSED;
+    ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    ok(tcItem.dwState == 0, "Expected zero dwState\n");
+
+    /* check with negative index to be sure */
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_PARAM;
+    ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
+
+    memset(&tcItem, 0xcc, sizeof(tcItem));
+    tcItem.mask = TCIF_PARAM;
+    ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem);
+    expect(FALSE, ret);
+    ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
 
 
-        /* TCIS_BUTTONPRESSED doesn't depend on tab style */
-        memset(&tcItem, 0, sizeof(tcItem));
-        tcItem.mask = TCIF_STATE;
-        tcItem.dwStateMask = TCIS_BUTTONPRESSED;
-        tcItem.dwState = TCIS_BUTTONPRESSED;
-        ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
-        tcItem.dwState = 0;
-        ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    tcItem.mask = TCIF_TEXT;
+    tcItem.pszText = &szText[0];
+    tcItem.cchTextMax = sizeof(szText);
+
+    strcpy(szText, "New Label");
+    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);
+
+    /* TCIS_BUTTONPRESSED doesn't depend on tab style */
+    memset(&tcItem, 0, sizeof(tcItem));
+    tcItem.mask = TCIF_STATE;
+    tcItem.dwStateMask = TCIS_BUTTONPRESSED;
+    tcItem.dwState = TCIS_BUTTONPRESSED;
+    ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
+    tcItem.dwState = 0;
+    ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
+    if (tcItem.dwState)
+    {
         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
         /* next highlight item, test that dwStateMask actually masks */
         tcItem.mask = TCIF_STATE;
         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
         /* next highlight item, test that dwStateMask actually masks */
         tcItem.mask = TCIF_STATE;
@@ -865,24 +893,91 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs)
         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
     }
         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
     }
+    else win_skip( "Item state mask not supported\n" );
 
 
-    /* Testing GetSet ToolTip */
-    {
-        HWND toolTip;
-        char toolTipText[32] = "ToolTip Text Test";
+    DestroyWindow(hTab);
+}
 
 
-        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+static void test_getset_tooltips(HWND parent_wnd, INT nTabs)
+{
+    HWND hTab, toolTip;
+    char toolTipText[32] = "ToolTip Text Test";
 
 
-        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");
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
+    ok(hTab != NULL, "Failed to create tab control\n");
 
 
-        SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0);
-        ok (NULL  == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
-        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);
-    }
+    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, 0, 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_misc(HWND parent_wnd, INT nTabs)
+{
+    HWND hTab;
+    RECT rTab;
+    INT nTabsRetrieved;
+    INT rowCount;
+    INT dpi;
+    HDC hdc;
+
+    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);
+    ok(SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1) > 0,"TCM_SETMINTABWIDTH returned < 0\n");
+    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");
+
+    hdc = GetDC(hTab);
+    dpi = GetDeviceCaps(hdc, LOGPIXELSX);
+    ReleaseDC(hTab, hdc);
+    CheckSize(hTab, dpi, -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);
 
     DestroyWindow(hTab);
 }
 
     DestroyWindow(hTab);
 }
@@ -903,6 +998,7 @@ static void test_adjustrect(HWND parent_wnd)
     r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0);
     expect(-1, r);
 }
     r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0);
     expect(-1, r);
 }
+
 static void test_insert_focus(HWND parent_wnd)
 {
     HWND hTab;
 static void test_insert_focus(HWND parent_wnd)
 {
     HWND hTab;
@@ -960,8 +1056,8 @@ static void test_insert_focus(HWND parent_wnd)
     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
     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);
+    ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", TRUE);
 
     DestroyWindow(hTab);
 }
 
     DestroyWindow(hTab);
 }
@@ -1010,7 +1106,7 @@ static void test_delete_focus(HWND parent_wnd)
     expect(-1, r);
 
     ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE);
     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);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", TRUE);
 
     DestroyWindow(hTab);
 }
 
     DestroyWindow(hTab);
 }
@@ -1078,6 +1174,28 @@ static void test_removeimage(HWND parent_wnd)
     DestroyIcon(hicon);
 }
 
     DestroyIcon(hicon);
 }
 
+static void test_delete_selection(HWND parent_wnd)
+{
+    HWND hTab;
+    DWORD ret;
+
+    hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
+    ok(hTab != NULL, "Failed to create tab control\n");
+
+    ret = SendMessage(hTab, TCM_SETCURSEL, 3, 0);
+    expect(0, ret);
+    ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
+    expect(3, ret);
+    /* delete selected item - selection goes to -1 */
+    ret = SendMessage(hTab, TCM_DELETEITEM, 3, 0);
+    expect(TRUE, ret);
+
+    ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
+    expect(-1, ret);
+
+    DestroyWindow(hTab);
+}
+
 START_TEST(tab)
 {
     HWND parent_wnd;
 START_TEST(tab)
 {
     HWND parent_wnd;
@@ -1108,13 +1226,19 @@ START_TEST(tab)
     parent_wnd = createParentWindow();
     ok(parent_wnd != NULL, "Failed to create parent window!\n");
 
     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_curfocus(parent_wnd, 5);
+    test_cursel(parent_wnd, 5);
+    test_extendedstyle(parent_wnd, 5);
+    test_unicodeformat(parent_wnd, 5);
+    test_getset_item(parent_wnd, 5);
+    test_getset_tooltips(parent_wnd, 5);
+    test_misc(parent_wnd, 5);
 
     test_adjustrect(parent_wnd);
 
     test_insert_focus(parent_wnd);
     test_delete_focus(parent_wnd);
 
     test_adjustrect(parent_wnd);
 
     test_insert_focus(parent_wnd);
     test_delete_focus(parent_wnd);
+    test_delete_selection(parent_wnd);
     test_removeimage(parent_wnd);
 
     DestroyWindow(parent_wnd);
     test_removeimage(parent_wnd);
 
     DestroyWindow(parent_wnd);
index 7e32af4..1789e5c 100644 (file)
@@ -15,7 +15,6 @@ extern void func_listview(void);
 extern void func_misc(void);
 extern void func_monthcal(void);
 extern void func_mru(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_progress(void);
 extern void func_propsheet(void);
 extern void func_rebar(void);
@@ -40,7 +39,6 @@ const struct test winetest_testlist[] =
     { "misc", func_misc },
     { "monthcal", func_monthcal },
     { "mru", func_mru },
     { "misc", func_misc },
     { "monthcal", func_monthcal },
     { "mru", func_mru },
-    { "msg", func_msg },
     { "progress", func_progress },
     { "propsheet", func_propsheet },
     { "rebar", func_rebar },
     { "progress", func_progress },
     { "propsheet", func_propsheet },
     { "rebar", func_rebar },
index 1946095..8311df5 100644 (file)
 
 #include "wine/test.h"
 
 
 #include "wine/test.h"
 
+#include "msg.h"
+
+#define PARENT_SEQ_INDEX       0
+#define NUM_MSG_SEQUENCES      1
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
 static HWND hMainWnd;
 static BOOL g_fBlockHotItemChange;
 static BOOL g_fReceivedHotItemChange;
 static BOOL g_fExpectedHotItemOld;
 static BOOL g_fExpectedHotItemNew;
 static DWORD g_dwExpectedDispInfoMask;
 static HWND hMainWnd;
 static BOOL g_fBlockHotItemChange;
 static BOOL g_fReceivedHotItemChange;
 static BOOL g_fExpectedHotItemOld;
 static BOOL g_fExpectedHotItemNew;
 static DWORD g_dwExpectedDispInfoMask;
+static BOOL g_ResetDispTextPtr;
+
+static const struct message ttgetdispinfo_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, TBN_GETINFOTIPA },
+    /* next line is todo, currently TTN_GETDISPINFOW is raised here */
+    { WM_NOTIFY, sent|id, 0, 0, TTN_GETDISPINFOA },
+    { 0 }
+};
 
 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
 
 
 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
 
@@ -56,7 +71,7 @@ static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
   p->iString = nString;
 }
 
   p->iString = nString;
 }
 
-static LRESULT MyWnd_Notify(LPARAM lParam)
+static LRESULT parent_wnd_notify(LPARAM lParam)
 {
     NMHDR *hdr = (NMHDR *)lParam;
     NMTBHOTITEM *nmhi;
 {
     NMHDR *hdr = (NMHDR *)lParam;
     NMTBHOTITEM *nmhi;
@@ -79,25 +94,65 @@ static LRESULT MyWnd_Notify(LPARAM lParam)
             ok(FALSE, "TBN_GETDISPINFOA received\n");
             break;
 
             ok(FALSE, "TBN_GETDISPINFOA received\n");
             break;
 
+        case TBN_GETINFOTIPA:
+        {
+            NMTBGETINFOTIPA *tbgit = (NMTBGETINFOTIPA*)lParam;
+
+            if (g_ResetDispTextPtr)
+            {
+                tbgit->pszText = NULL;
+                return 0;
+            }
+            break;
+        }
         case TBN_GETDISPINFOW:
             nmdisp = (NMTBDISPINFOA *)lParam;
 
             compare(nmdisp->dwMask, g_dwExpectedDispInfoMask, "%x");
         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;
 }
 
             ok(nmdisp->pszText == NULL, "pszText is not NULL\n");
         break;
     }
     return 0;
 }
 
-static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 {
-    switch (msg)
+    static LONG defwndproc_counter = 0;
+    struct message msg;
+    LRESULT ret;
+
+    msg.message = message;
+    msg.flags = sent|wparam|lparam;
+    if (defwndproc_counter) msg.flags |= defwinproc;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
+
+    /* log system messages, except for painting */
+    if (message < WM_USER &&
+        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);
+        add_message(sequences, PARENT_SEQ_INDEX, &msg);
+    }
+
+    switch (message)
     {
         case WM_NOTIFY:
     {
         case WM_NOTIFY:
-            return MyWnd_Notify(lParam);
+            return parent_wnd_notify(lParam);
     }
     }
-    return DefWindowProcA(hWnd, msg, wParam, lParam);
+
+    defwndproc_counter++;
+    ret = DefWindowProcA(hWnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
 }
 
 static void basic_test(void)
 }
 
 static void basic_test(void)
@@ -163,7 +218,7 @@ static void basic_test(void)
 
 static void rebuild_toolbar(HWND *hToolbar)
 {
 
 static void rebuild_toolbar(HWND *hToolbar)
 {
-    if (*hToolbar != NULL)
+    if (*hToolbar)
         DestroyWindow(*hToolbar);
     *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
         hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
         DestroyWindow(*hToolbar);
     *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
         hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL);
@@ -374,6 +429,8 @@ static void test_add_bitmap(void)
     addbmp.hInst = HINST_COMMCTRL;
     addbmp.nID = IDB_STD_SMALL_COLOR;
     rebuild_toolbar(&hToolbar);
     addbmp.hInst = HINST_COMMCTRL;
     addbmp.nID = IDB_STD_SMALL_COLOR;
     rebuild_toolbar(&hToolbar);
+    ImageList_Destroy(himl);
+
     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");
     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");
@@ -415,7 +472,7 @@ static void test_add_bitmap(void)
                 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, \
                 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"); \
+            "Too many strings in table\n"); \
     }
 
 static void test_add_string(void)
     }
 
 static void test_add_string(void)
@@ -432,10 +489,17 @@ static void test_add_string(void)
     HWND hToolbar = NULL;
     TBBUTTON button;
     int ret;
     HWND hToolbar = NULL;
     TBBUTTON button;
     int ret;
+    CHAR buf[260];
 
     rebuild_toolbar(&hToolbar);
     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
 
     rebuild_toolbar(&hToolbar);
     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test1);
     ok(ret == 0, "TB_ADDSTRINGA - unexpected return %d\n", ret);
+    ret = SendMessageA(hToolbar, TB_GETSTRING, MAKEWPARAM(260, 1), (LPARAM)buf);
+    if (ret == 0)
+    {
+        win_skip("TB_GETSTRING needs 5.80\n");
+        return;
+    }
     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(2, ret1);
     ret = SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)test2);
     ok(ret == 2, "TB_ADDSTRINGA - unexpected return %d\n", ret);
@@ -734,6 +798,22 @@ static tbsize_result_t tbsize_results[] =
 
 static int tbsize_numtests = 0;
 
 
 static int tbsize_numtests = 0;
 
+typedef struct
+{
+    int test_num;
+    int rect_index;
+    RECT rcButton;
+} tbsize_alt_result_t;
+
+static tbsize_alt_result_t tbsize_alt_results[] =
+{
+  { 5, 2, { 0, 24, 8, 29 } },
+  { 20, 1, { 100, 2, 107, 102 } },
+  { 20, 2, { 107, 2, 207, 102 } }
+};
+
+static int tbsize_alt_numtests = 0;
+
 #define check_sizes_todo(todomask) { \
         RECT rc; \
         int buttonCount, i, mask=(todomask); \
 #define check_sizes_todo(todomask) { \
         RECT rc; \
         int buttonCount, i, mask=(todomask); \
@@ -745,7 +825,11 @@ static int tbsize_numtests = 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"); \
         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)) { \
+            if (broken(tbsize_alt_numtests < sizeof(tbsize_alt_results)/sizeof(tbsize_alt_results[0]) && \
+                       memcmp(&rc, &tbsize_alt_results[tbsize_alt_numtests].rcButton, sizeof(RECT)) == 0)) { \
+                win_skip("Alternate rect found\n"); \
+                tbsize_alt_numtests++; \
+            } else if (!(mask&1)) { \
                 check_rect("button", rc, res->rcButtons[i]); \
             } else {\
                 todo_wine { check_rect("button", rc, res->rcButtons[i]); } \
                 check_rect("button", rc, res->rcButtons[i]); \
             } else {\
                 todo_wine { check_rect("button", rc, res->rcButtons[i]); } \
@@ -954,6 +1038,7 @@ static void test_sizes(void)
 
     rebuild_toolbar(&hToolbar);
     ImageList_Destroy(himl);
 
     rebuild_toolbar(&hToolbar);
     ImageList_Destroy(himl);
+    ImageList_Destroy(himl2);
 
     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_ADDBUTTONS, 1, (LPARAM)&buttons3[3]);
     ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n");
@@ -995,10 +1080,17 @@ static void test_sizes(void)
     tbinfo.cx = 672;
     tbinfo.cbSize = sizeof(TBBUTTONINFO);
     tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX;
     tbinfo.cx = 672;
     tbinfo.cbSize = sizeof(TBBUTTONINFO);
     tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX;
-    ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
-    ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
-    SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
-    check_sizes();
+    if (SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo))
+    {
+        ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
+        SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0);
+        check_sizes();
+    }
+    else  /* TBIF_BYINDEX probably not supported, confirm that this was the reason for the failure */
+    {
+        tbinfo.dwMask = TBIF_SIZE;
+        ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 33, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n");
+    }
 
     DestroyWindow(hToolbar);
 }
 
     DestroyWindow(hToolbar);
 }
@@ -1049,21 +1141,24 @@ static void restore_recalc_state(HWND hToolbar)
 
 static void test_recalc(void)
 {
 
 static void test_recalc(void)
 {
-    HWND hToolbar;
+    HWND hToolbar = NULL;
     TBBUTTONINFO bi;
     CHAR test[] = "Test";
     const int EX_STYLES_COUNT = 5;
     int i;
     TBBUTTONINFO bi;
     CHAR test[] = "Test";
     const int EX_STYLES_COUNT = 5;
     int i;
+    BOOL recalc;
 
     /* Like TB_ADDBUTTONS tested in test_sized, inserting a button without text
      * results in a relayout, while adding one with text forces a recalc */
     prepare_recalc_test(&hToolbar);
     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[0]);
 
     /* Like TB_ADDBUTTONS tested in test_sized, inserting a button without text
      * results in a relayout, while adding one with text forces a recalc */
     prepare_recalc_test(&hToolbar);
     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[0]);
-    ok(!did_recalc(hToolbar), "Unexpected recalc - adding button without text\n");
+    recalc = did_recalc(hToolbar);
+    ok(!recalc, "Unexpected recalc - adding button without text\n");
 
     prepare_recalc_test(&hToolbar);
     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[3]);
 
     prepare_recalc_test(&hToolbar);
     SendMessage(hToolbar, TB_INSERTBUTTON, 1, (LPARAM)&buttons3[3]);
-    ok(did_recalc(hToolbar), "Expected a recalc - adding button with text\n");
+    recalc = did_recalc(hToolbar);
+    ok(recalc, "Expected a recalc - adding button with text\n");
 
     /* TB_SETBUTTONINFO, even when adding a text, results only in a relayout */
     prepare_recalc_test(&hToolbar);
 
     /* TB_SETBUTTONINFO, even when adding a text, results only in a relayout */
     prepare_recalc_test(&hToolbar);
@@ -1071,7 +1166,8 @@ static void test_recalc(void)
     bi.dwMask = TBIF_TEXT;
     bi.pszText = test;
     SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&bi);
     bi.dwMask = TBIF_TEXT;
     bi.pszText = test;
     SendMessage(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&bi);
-    ok(!did_recalc(hToolbar), "Unexpected recalc - setting a button text\n");
+    recalc = did_recalc(hToolbar);
+    ok(!recalc, "Unexpected recalc - setting a button text\n");
 
     /* most extended styled doesn't force a recalc (testing all the bits gives
      * the same results, but prints some ERRs while testing) */
 
     /* most extended styled doesn't force a recalc (testing all the bits gives
      * the same results, but prints some ERRs while testing) */
@@ -1082,22 +1178,31 @@ static void test_recalc(void)
         prepare_recalc_test(&hToolbar);
         expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
         SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, (1 << i));
         prepare_recalc_test(&hToolbar);
         expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
         SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, (1 << i));
-        ok(!did_recalc(hToolbar), "Unexpected recalc - setting bit %d\n", i);
+        recalc = did_recalc(hToolbar);
+        ok(!recalc, "Unexpected recalc - setting bit %d\n", i);
         SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
         SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
-        ok(!did_recalc(hToolbar), "Unexpected recalc - clearing bit %d\n", i);
+        recalc = did_recalc(hToolbar);
+        ok(!recalc, "Unexpected recalc - clearing bit %d\n", i);
         expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
     }
 
     /* TBSTYLE_EX_MIXEDBUTTONS does a recalc on change */
     prepare_recalc_test(&hToolbar);
     SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
         expect(0, (int)SendMessage(hToolbar, TB_GETEXTENDEDSTYLE, 0, 0));
     }
 
     /* TBSTYLE_EX_MIXEDBUTTONS does a recalc on change */
     prepare_recalc_test(&hToolbar);
     SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
-    ok(did_recalc(hToolbar), "Expected a recalc - setting TBSTYLE_EX_MIXEDBUTTONS\n");
-    restore_recalc_state(hToolbar);
-    SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
-    ok(!did_recalc(hToolbar), "Unexpected recalc - setting TBSTYLE_EX_MIXEDBUTTONS again\n");
-    restore_recalc_state(hToolbar);
-    SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
-    ok(did_recalc(hToolbar), "Expected a recalc - clearing TBSTYLE_EX_MIXEDBUTTONS\n");
+    recalc = did_recalc(hToolbar);
+    if (recalc)
+    {
+        ok(recalc, "Expected a recalc - setting TBSTYLE_EX_MIXEDBUTTONS\n");
+        restore_recalc_state(hToolbar);
+        SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
+        recalc = did_recalc(hToolbar);
+        ok(!recalc, "Unexpected recalc - setting TBSTYLE_EX_MIXEDBUTTONS again\n");
+        restore_recalc_state(hToolbar);
+        SendMessage(hToolbar, TB_SETEXTENDEDSTYLE, 0, 0);
+        recalc = did_recalc(hToolbar);
+        ok(recalc, "Expected a recalc - clearing TBSTYLE_EX_MIXEDBUTTONS\n");
+    }
+    else win_skip( "No recalc on TBSTYLE_EX_MIXEDBUTTONS\n" );
 
     /* undocumented exstyle 0x2 seems to changes the top margin, what
      * interferes with these tests */
 
     /* undocumented exstyle 0x2 seems to changes the top margin, what
      * interferes with these tests */
@@ -1117,8 +1222,8 @@ static void test_getbuttoninfo(void)
         int ret;
 
         tbi.cbSize = i;
         int ret;
 
         tbi.cbSize = i;
-        tbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
-        ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 0, (LPARAM)&tbi);
+        tbi.dwMask = TBIF_COMMAND;
+        ret = (int)SendMessage(hToolbar, TB_GETBUTTONINFO, 1, (LPARAM)&tbi);
         if (i == sizeof(TBBUTTONINFO)) {
             compare(ret, 0, "%d");
         } else {
         if (i == sizeof(TBBUTTONINFO)) {
             compare(ret, 0, "%d");
         } else {
@@ -1189,7 +1294,7 @@ static void test_dispinfo(void)
     rebuild_toolbar(&hToolbar);
     SendMessageA(hToolbar, TB_LOADIMAGES, IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
     SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp);
     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;
+    g_dwExpectedDispInfoMask = TBNF_IMAGE;
     /* 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");
     /* 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");
@@ -1281,6 +1386,12 @@ static void test_getstring(void)
     ok(hToolbar != NULL, "Toolbar creation problem\n");
 
     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0);
     ok(hToolbar != NULL, "Toolbar creation problem\n");
 
     r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), 0);
+    if (r == 0)
+    {
+        win_skip("TB_GETSTRING and TB_GETSTRINGW need 5.80\n");
+        DestroyWindow(hToolbar);
+        return;
+    }
     expect(-1, r);
     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
     expect(-1, r);
     expect(-1, r);
     r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), 0);
     expect(-1, r);
@@ -1300,12 +1411,46 @@ static void test_getstring(void)
     DestroyWindow(hToolbar);
 }
 
     DestroyWindow(hToolbar);
 }
 
+static void test_tooltip(void)
+{
+    HWND hToolbar = NULL;
+    const TBBUTTON buttons_disp[] = {
+        {-1, 20, TBSTATE_ENABLED, 0, {0, }, 0, -1},
+        {0,  21, TBSTATE_ENABLED, 0, {0, }, 0, -1},
+    };
+    NMTTDISPINFOW nmtti;
+
+    rebuild_toolbar(&hToolbar);
+
+    SendMessageA(hToolbar, TB_ADDBUTTONS, 2, (LPARAM)buttons_disp);
+
+    /* W used to get through toolbar code that assumes tooltip is always Unicode */
+    memset(&nmtti, 0, sizeof(nmtti));
+    nmtti.hdr.code = TTN_GETDISPINFOW;
+    nmtti.hdr.idFrom = 20;
+
+    SendMessageA(hToolbar, CCM_SETUNICODEFORMAT, FALSE, 0);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
+    ok_sequence(sequences, PARENT_SEQ_INDEX, ttgetdispinfo_parent_seq,
+                "dispinfo from tooltip", TRUE);
+
+    g_ResetDispTextPtr = TRUE;
+    SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
+    g_ResetDispTextPtr = FALSE;
+
+    DestroyWindow(hToolbar);
+}
+
 START_TEST(toolbar)
 {
     WNDCLASSA wc;
     MSG msg;
     RECT rc;
 START_TEST(toolbar)
 {
     WNDCLASSA wc;
     MSG msg;
     RECT rc;
-  
+
+    init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
     InitCommonControls();
   
     wc.style = CS_HREDRAW | CS_VREDRAW;
     InitCommonControls();
   
     wc.style = CS_HREDRAW | CS_VREDRAW;
@@ -1316,11 +1461,11 @@ START_TEST(toolbar)
     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
     wc.hCursor = LoadCursorA(NULL, IDC_IBEAM);
     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
     wc.lpszMenuName = NULL;
-    wc.lpszClassName = "MyTestWnd";
-    wc.lpfnWndProc = MyWndProc;
+    wc.lpszClassName = "Toolbar test parent";
+    wc.lpfnWndProc = parent_wnd_proc;
     RegisterClassA(&wc);
     
     RegisterClassA(&wc);
     
-    hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
+    hMainWnd = CreateWindowExA(0, "Toolbar test parent", "Blah", WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
     GetClientRect(hMainWnd, &rc);
     ShowWindow(hMainWnd, SW_SHOW);
       CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
     GetClientRect(hMainWnd, &rc);
     ShowWindow(hMainWnd, SW_SHOW);
@@ -1336,6 +1481,7 @@ START_TEST(toolbar)
     test_dispinfo();
     test_setrows();
     test_getstring();
     test_dispinfo();
     test_setrows();
     test_getstring();
+    test_tooltip();
 
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
 
     PostQuitMessage(0);
     while(GetMessageA(&msg,0,0,0)) {
index 2b4f43f..8ca3f7b 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "wine/test.h"
 
 
 #include "wine/test.h"
 
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+
 static void test_create_tooltip(void)
 {
     HWND parent, hwnd;
 static void test_create_tooltip(void)
 {
     HWND parent, hwnd;
@@ -42,7 +44,8 @@ static void test_create_tooltip(void)
     trace("style = %08x\n", style);
     exp_style = 0x7fffffff | WS_POPUP;
     exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
     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 %08x/%08x\n", style, exp_style);
+    ok(style == exp_style || broken(style == (exp_style | WS_BORDER)), /* nt4 */
+       "wrong style %08x/%08x\n", style, exp_style);
 
     DestroyWindow(hwnd);
 
 
     DestroyWindow(hwnd);
 
@@ -142,7 +145,6 @@ static void test_customdraw(void) {
         /* Invalid notification responses */
         {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
         {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
         /* Invalid notification responses */
         {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
         {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
-        {CDRF_NOTIFYSUBITEMDRAW, TEST_CDDS_PREPAINT},
         {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
     };
 
         {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
     };
 
@@ -168,6 +170,7 @@ static void test_customdraw(void) {
         iterationNumber++) {
 
        HWND parent, hwndTip;
         iterationNumber++) {
 
        HWND parent, hwndTip;
+       RECT rect;
        TOOLINFO toolInfo = { 0 };
 
        /* Create a main window */
        TOOLINFO toolInfo = { 0 };
 
        /* Create a main window */
@@ -201,7 +204,7 @@ static void test_customdraw(void) {
              SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 
        /* Create a tool */
              SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 
        /* Create a tool */
-       toolInfo.cbSize = sizeof(TOOLINFO);
+       toolInfo.cbSize = TTTOOLINFO_V1_SIZE;
        toolInfo.hwnd = parent;
        toolInfo.hinst = GetModuleHandleA(NULL);
        toolInfo.uFlags = TTF_SUBCLASS;
        toolInfo.hwnd = parent;
        toolInfo.hinst = GetModuleHandleA(NULL);
        toolInfo.uFlags = TTF_SUBCLASS;
@@ -216,13 +219,18 @@ static void test_customdraw(void) {
        SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
 
        /* Put cursor inside window, tooltip will appear immediately */
        SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
 
        /* Put cursor inside window, tooltip will appear immediately */
-       SetCursorPos(100, 100);
+       GetWindowRect( parent, &rect );
+       SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 );
        flush_events(200);
 
        flush_events(200);
 
-       /* Check CustomDraw results */
-       ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls,
-          "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages,
-          expectedResults[iterationNumber].ExpectedCalls);
+       if (CD_Stages)
+       {
+           /* Check CustomDraw results */
+           ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls ||
+              broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */
+              "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages,
+              expectedResults[iterationNumber].ExpectedCalls);
+       }
 
        /* Clean up */
        DestroyWindow(hwndTip);
 
        /* Clean up */
        DestroyWindow(hwndTip);
@@ -232,14 +240,63 @@ static void test_customdraw(void) {
 
 }
 
 
 }
 
+static const CHAR testcallbackA[]  = "callback";
+
+static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    if (message == WM_NOTIFY && lParam)
+    {
+        NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
+
+        if (ttnmdi->hdr.code == TTN_GETDISPINFOA)
+            lstrcpy(ttnmdi->lpszText, testcallbackA);
+    }
+
+    return DefWindowProcA(hwnd, message, wParam, lParam);
+}
+
+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, IDC_ARROW);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "Tooltips test parent class";
+    return RegisterClassA(&cls);
+}
+
+static HWND create_parent_window(void)
+{
+    if (!register_parent_wnd_class())
+        return NULL;
+
+    return CreateWindowEx(0, "Tooltips test parent class",
+                          "Tooltips test parent window",
+                          WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                          WS_MAXIMIZEBOX | WS_VISIBLE,
+                          0, 0, 100, 100,
+                          GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
+}
+
 static void test_gettext(void)
 {
 static void test_gettext(void)
 {
-    HWND hwnd;
+    HWND hwnd, notify;
     TTTOOLINFOA toolinfoA;
     TTTOOLINFOW toolinfoW;
     LRESULT r;
     TTTOOLINFOA toolinfoA;
     TTTOOLINFOW toolinfoW;
     LRESULT r;
-    char bufA[10] = "";
+    CHAR bufA[10] = "";
     WCHAR bufW[10] = { 0 };
     WCHAR bufW[10] = { 0 };
+    static const CHAR testtipA[] = "testtip";
+
+    notify = create_parent_window();
+    ok(notify != NULL, "Expected notification window to be created\n");
 
     /* For bug 14790 - lpszText is NULL */
     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
 
     /* For bug 14790 - lpszText is NULL */
     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
@@ -247,6 +304,8 @@ static void test_gettext(void)
                            NULL, NULL, NULL, 0);
     assert(hwnd);
 
                            NULL, NULL, NULL, 0);
     assert(hwnd);
 
+    /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */
+    /* otherwise it crashes on the NULL lpszText */
     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
     toolinfoA.hwnd = NULL;
     toolinfoA.hinst = GetModuleHandleA(NULL);
     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
     toolinfoA.hwnd = NULL;
     toolinfoA.hinst = GetModuleHandleA(NULL);
@@ -256,7 +315,6 @@ static void test_gettext(void)
     toolinfoA.lParam = 0xdeadbeef;
     GetClientRect(hwnd, &toolinfoA.rect);
     r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
     toolinfoA.lParam = 0xdeadbeef;
     GetClientRect(hwnd, &toolinfoA.rect);
     r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
-    ok(r, "Adding the tool to the tooltip failed\n");
     if (r)
     {
         toolinfoA.hwnd = NULL;
     if (r)
     {
         toolinfoA.hwnd = NULL;
@@ -265,8 +323,65 @@ static void test_gettext(void)
         SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
         ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n");
     }
         SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
         ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n");
     }
+    else
+    {
+        win_skip( "Old comctl32, not testing NULL text\n" );
+        DestroyWindow( hwnd );
+        return;
+    }
+
+    /* add another tool with text */
+    toolinfoA.cbSize = sizeof(TTTOOLINFOA);
+    toolinfoA.hwnd = NULL;
+    toolinfoA.hinst = GetModuleHandleA(NULL);
+    toolinfoA.uFlags = 0;
+    toolinfoA.uId = 0x1235ABCD;
+    strcpy(bufA, testtipA);
+    toolinfoA.lpszText = bufA;
+    toolinfoA.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &toolinfoA.rect);
+    r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    if (r)
+    {
+        DWORD length;
+
+        length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
+        ok(length == 0, "Expected 0, got %d\n", length);
+
+        toolinfoA.hwnd = NULL;
+        toolinfoA.uId = 0x1235ABCD;
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
+        ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n");
+
+        length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
+        ok(length == 0, "Expected 0, got %d\n", length);
+    }
+
+    /* add another with callback text */
+    toolinfoA.cbSize = sizeof(TTTOOLINFOA);
+    toolinfoA.hwnd = notify;
+    toolinfoA.hinst = GetModuleHandleA(NULL);
+    toolinfoA.uFlags = 0;
+    toolinfoA.uId = 0x1236ABCD;
+    toolinfoA.lpszText = LPSTR_TEXTCALLBACKA;
+    toolinfoA.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &toolinfoA.rect);
+    r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    if (r)
+    {
+        toolinfoA.hwnd = notify;
+        toolinfoA.uId = 0x1236ABCD;
+        toolinfoA.lpszText = bufA;
+        SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
+        ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0,
+           "lpszText should be an (%s) string\n", testcallbackA);
+    }
 
     DestroyWindow(hwnd);
 
     DestroyWindow(hwnd);
+    DestroyWindow(notify);
 
     SetLastError(0xdeadbeef);
     hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
 
     SetLastError(0xdeadbeef);
     hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
@@ -303,6 +418,208 @@ static void test_gettext(void)
     DestroyWindow(hwnd);
 }
 
     DestroyWindow(hwnd);
 }
 
+static void test_ttm_gettoolinfo(void)
+{
+    TTTOOLINFOA ti;
+    TTTOOLINFOW tiW;
+    HWND hwnd;
+    DWORD r;
+
+    hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
+                           10, 10, 300, 100,
+                           NULL, NULL, NULL, 0);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE;
+    ti.hwnd = NULL;
+    ti.hinst = GetModuleHandleA(NULL);
+    ti.uFlags = 0;
+    ti.uId = 0x1234ABCD;
+    ti.lpszText = NULL;
+    ti.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &ti.rect);
+    r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+    ok(r, "Adding the tool to the tooltip failed\n");
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE;
+    ti.lParam = 0xaaaaaaaa;
+    r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
+    ok(r, "Getting tooltip info failed\n");
+    ok(0xdeadbeef == ti.lParam ||
+       broken(0xdeadbeef != ti.lParam), /* comctl32 < 5.81 */
+       "Expected 0xdeadbeef, got %lx\n", ti.lParam);
+
+    tiW.cbSize = TTTOOLINFOW_V2_SIZE;
+    tiW.hwnd = NULL;
+    tiW.uId = 0x1234ABCD;
+    tiW.lParam = 0xaaaaaaaa;
+    r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW);
+    ok(r, "Getting tooltip info failed\n");
+    ok(0xdeadbeef == tiW.lParam ||
+       broken(0xdeadbeef != tiW.lParam), /* comctl32 < 5.81 */
+       "Expected 0xdeadbeef, got %lx\n", tiW.lParam);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE;
+    ti.uId = 0x1234ABCD;
+    ti.lParam = 0xaaaaaaaa;
+    SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE;
+    ti.lParam = 0xdeadbeef;
+    r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
+    ok(r, "Getting tooltip info failed\n");
+    ok(0xaaaaaaaa == ti.lParam ||
+       broken(0xaaaaaaaa != ti.lParam), /* comctl32 < 5.81 */
+       "Expected 0xaaaaaaaa, got %lx\n", ti.lParam);
+
+    DestroyWindow(hwnd);
+
+    /* 1. test size parameter validation rules (ansi messages) */
+    hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
+                           10, 10, 300, 100,
+                           NULL, NULL, NULL, 0);
+
+    ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
+    ti.hwnd = NULL;
+    ti.hinst = GetModuleHandleA(NULL);
+    ti.uFlags = 0;
+    ti.uId = 0x1234ABCD;
+    ti.lpszText = NULL;
+    ti.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &ti.rect);
+    r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+
+    ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
+    ti.hwnd = NULL;
+    ti.uId = 0x1234ABCD;
+    SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
+    r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(0, r);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
+    ti.hwnd = NULL;
+    ti.hinst = GetModuleHandleA(NULL);
+    ti.uFlags = 0;
+    ti.uId = 0x1234ABCD;
+    ti.lpszText = NULL;
+    ti.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &ti.rect);
+    r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
+    ti.hwnd = NULL;
+    ti.uId = 0x1234ABCD;
+    SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
+    r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(0, r);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
+    ti.hwnd = NULL;
+    ti.hinst = GetModuleHandleA(NULL);
+    ti.uFlags = 0;
+    ti.uId = 0x1234ABCD;
+    ti.lpszText = NULL;
+    ti.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &ti.rect);
+    r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+
+    ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
+    ti.hwnd = NULL;
+    ti.uId = 0x1234ABCD;
+    SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
+    r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(0, r);
+
+    DestroyWindow(hwnd);
+
+    /* 2. test size parameter validation rules (w-messages) */
+    hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
+                           10, 10, 300, 100,
+                           NULL, NULL, NULL, 0);
+    if(!hwnd)
+    {
+        win_skip("CreateWindowExW() not supported. Skipping.\n");
+        return;
+    }
+
+    tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
+    tiW.hwnd = NULL;
+    tiW.hinst = GetModuleHandleA(NULL);
+    tiW.uFlags = 0;
+    tiW.uId = 0x1234ABCD;
+    tiW.lpszText = NULL;
+    tiW.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &tiW.rect);
+    r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+
+    tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
+    tiW.hwnd = NULL;
+    tiW.uId = 0x1234ABCD;
+    SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(0, r);
+
+    tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
+    tiW.hwnd = NULL;
+    tiW.hinst = GetModuleHandleA(NULL);
+    tiW.uFlags = 0;
+    tiW.uId = 0x1234ABCD;
+    tiW.lpszText = NULL;
+    tiW.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &tiW.rect);
+    r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+
+    tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
+    tiW.hwnd = NULL;
+    tiW.uId = 0x1234ABCD;
+    SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(0, r);
+
+    tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
+    tiW.hwnd = NULL;
+    tiW.hinst = GetModuleHandleA(NULL);
+    tiW.uFlags = 0;
+    tiW.uId = 0x1234ABCD;
+    tiW.lpszText = NULL;
+    tiW.lParam = 0xdeadbeef;
+    GetClientRect(hwnd, &tiW.rect);
+    r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW);
+    ok(r, "Adding the tool to the tooltip failed\n");
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+    /* looks like TTM_DELTOOLW doesn't work with invalid size */
+    tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
+    tiW.hwnd = NULL;
+    tiW.uId = 0x1234ABCD;
+    SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(1, r);
+
+    tiW.cbSize = TTTOOLINFOW_V2_SIZE;
+    tiW.hwnd = NULL;
+    tiW.uId = 0x1234ABCD;
+    SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
+    r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
+    expect(0, r);
+
+    DestroyWindow(hwnd);
+}
+
 START_TEST(tooltips)
 {
     InitCommonControls();
 START_TEST(tooltips)
 {
     InitCommonControls();
@@ -310,4 +627,5 @@ START_TEST(tooltips)
     test_create_tooltip();
     test_customdraw();
     test_gettext();
     test_create_tooltip();
     test_customdraw();
     test_gettext();
+    test_ttm_gettoolinfo();
 }
 }
index d94ffe9..68261d8 100644 (file)
 #define PARENT_SEQ_INDEX 0
 #define TRACKBAR_SEQ_INDEX 1
 
 #define PARENT_SEQ_INDEX 0
 #define TRACKBAR_SEQ_INDEX 1
 
+HWND hWndParent;
 
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCE];
 
 
 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_QUERYNEWPALETTE, sent|optional },
-    { 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 create_trackbar_wnd_seq[] = {
     {0}
 };
@@ -81,12 +59,12 @@ static const struct message parent_create_trackbar_wnd_seq[] = {
 
 static const struct message parent_new_window_test_seq[] = {
     { WM_QUERYNEWPALETTE, sent|optional },
 
 static const struct message parent_new_window_test_seq[] = {
     { WM_QUERYNEWPALETTE, sent|optional },
-    { WM_WINDOWPOSCHANGING, sent},
-    { WM_NCACTIVATE, sent},
-    { PBT_APMRESUMECRITICAL, sent},
+    { WM_WINDOWPOSCHANGING, sent|optional},
+    { WM_NCACTIVATE, sent|optional},
+    { PBT_APMRESUMECRITICAL, sent|optional},
     { WM_IME_SETCONTEXT, sent|defwinproc|optional},
     { WM_IME_NOTIFY, sent|defwinproc|optional},
     { WM_IME_SETCONTEXT, sent|defwinproc|optional},
     { WM_IME_NOTIFY, sent|defwinproc|optional},
-    { WM_SETFOCUS, sent|defwinproc},
+    { WM_SETFOCUS, sent|defwinproc|optional},
     { WM_NOTIFYFORMAT, sent},
     { WM_QUERYUISTATE, sent|optional},
     {0}
     { WM_NOTIFYFORMAT, sent},
     { WM_QUERYUISTATE, sent|optional},
     {0}
@@ -386,11 +364,6 @@ static const struct message ignore_selection_test_seq[] = {
     {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;
 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
     static LONG defwndproc_counter = 0;
     LRESULT ret;
@@ -452,7 +425,7 @@ static HWND create_parent_window(void){
 }
 
 static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
 }
 
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -467,36 +440,27 @@ static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
     add_message(sequences, TRACKBAR_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
     add_message(sequences, TRACKBAR_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
 
     return ret;
 }
 
 static HWND create_trackbar(DWORD style, HWND parent){
     defwndproc_counter--;
 
     return ret;
 }
 
 static HWND create_trackbar(DWORD style, HWND parent){
-    struct subclass_info *info;
     HWND hWndTrack;
     HWND hWndTrack;
+    WNDPROC oldproc;
     RECT rect;
 
     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);
 
     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);
+    if (!hWndTrack) return NULL;
 
 
-    SetWindowLongPtrA(hWndTrack, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hWndTrack, GWLP_WNDPROC, (LONG_PTR)trackbar_subclass_proc);
+    SetWindowLongPtrA(hWndTrack, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     return hWndTrack;
 }
 
     return hWndTrack;
 }
@@ -785,40 +749,63 @@ static void test_thumb_length(HWND hWndTrackbar){
 static void test_tic_settings(HWND hWndTrackbar){
     int r;
 
 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 */
     /* 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_GETRANGEMAX, 0, 0);
+    expect(10, r);
+    r = SendMessage(hWndTrackbar, TBM_GETRANGEMIN, 0, 0);
+    expect(5, r);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCE);
     r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 0);
     ok(r == FALSE, "Expected FALSE, got %d\n", r);
     r = SendMessage(hWndTrackbar, TBM_SETTIC, 0, 5);
     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);
-    }
+    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_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);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0);
     expect(6, r);
     SendMessage(hWndTrackbar, TBM_SETTICFREQ, 5, 0);
     expect(6, r);
     SendMessage(hWndTrackbar, TBM_SETTICFREQ, 5, 0);
-    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0);
     expect(3, r);
     SendMessage(hWndTrackbar, TBM_SETTICFREQ, 15, 0);
     expect(3, r);
     SendMessage(hWndTrackbar, TBM_SETTICFREQ, 15, 0);
-    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0,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 */
     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);
+    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);
     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);
+
+    /* range [0,0], freq = 1 */
+    SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 0);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0);
+    SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0);
+    expect(2, r);
+    /* range [0,1], freq = 1 */
+    SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 1);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0);
+    SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0);
+    expect(2, r);
+    /* range [0,2], freq = 1 */
+    SendMessage(hWndTrackbar, TBM_SETRANGEMAX, TRUE, 2);
+    SendMessage(hWndTrackbar, TBM_SETRANGEMIN, TRUE, 0);
+    SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0);
+    r = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0);
+    expect(3, r);
 }
 
 static void test_tic_placement(HWND hWndTrackbar){
 }
 
 static void test_tic_placement(HWND hWndTrackbar){
@@ -846,9 +833,7 @@ static void test_tic_placement(HWND hWndTrackbar){
     r = SendMessage(hWndTrackbar, TBM_GETTIC, 2,0);
     expect(4, r);
     r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0);
     r = SendMessage(hWndTrackbar, TBM_GETTIC, 2,0);
     expect(4, r);
     r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0);
-    todo_wine{
-        expect(-1, r);
-    }
+    expect(-1, r);
 
     /* test TBM_GETTICPIC */
     r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 0, 0);
 
     /* test TBM_GETTICPIC */
     r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 0, 0);
@@ -869,15 +854,13 @@ static void test_tool_tips(HWND hWndTrackbar){
     flush_sequences(sequences, NUM_MSG_SEQUENCE);
     /* testing TBM_SETTIPSIDE */
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_TOP, 0);
     flush_sequences(sequences, NUM_MSG_SEQUENCE);
     /* testing TBM_SETTIPSIDE */
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_TOP, 0);
-    todo_wine{
-        expect(0, r);
-    }
+    expect(TBTS_TOP, r);
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_LEFT, 0);
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_LEFT, 0);
-    expect(0, r);
+    expect(TBTS_TOP, r);
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_BOTTOM, 0);
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_BOTTOM, 0);
-    expect(1, r);
+    expect(TBTS_LEFT, r);
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_RIGHT, 0);
     r = SendMessage(hWndTrackbar, TBM_SETTIPSIDE, TBTS_RIGHT, 0);
-    expect(2, r);
+    expect(TBTS_BOTTOM, r);
 
     /* testing TBM_SETTOOLTIPS */
     hWndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, 0,
 
     /* testing TBM_SETTOOLTIPS */
     hWndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, 0,
@@ -967,17 +950,31 @@ static void test_ignore_selection(HWND hWndTrackbar){
     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent ignore selection setting test sequence", FALSE);
 }
 
     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent ignore selection setting test sequence", FALSE);
 }
 
+static void test_initial_state(void)
+{
+    HWND hWnd;
+    DWORD ret;
+
+    hWnd = create_trackbar(0, hWndParent);
+
+    ret = SendMessage(hWnd, TBM_GETNUMTICS, 0, 0);
+    expect(2, ret);
+    ret = SendMessage(hWnd, TBM_GETTIC, 0, 0);
+    expect(-1, ret);
+    ret = SendMessage(hWnd, TBM_GETTICPOS, 0, 0);
+    expect(-1, ret);
+
+    DestroyWindow(hWnd);
+}
+
 START_TEST(trackbar)
 {
     DWORD style = WS_VISIBLE | TBS_TOOLTIPS | TBS_ENABLESELRANGE | TBS_FIXEDLENGTH | TBS_AUTOTICKS;
     HWND hWndTrackbar;
 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();
 
 
     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");
     /* create parent window */
     hWndParent = create_parent_window();
     ok(hWndParent != NULL, "Failed to create parent Window!\n");
@@ -987,7 +984,6 @@ START_TEST(trackbar)
         return;
     }
 
         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 */
     flush_sequences(sequences, NUM_MSG_SEQUENCE);
 
     /* create trackbar with set styles */
@@ -1036,5 +1032,7 @@ START_TEST(trackbar)
 
     DestroyWindow(hWndTrackbar);
 
 
     DestroyWindow(hWndTrackbar);
 
+    test_initial_state();
+
     DestroyWindow(hWndParent);
 }
     DestroyWindow(hWndParent);
 }
index 05a5237..848d4ca 100644 (file)
 const char *TEST_CALLBACK_TEXT = "callback_text";
 
 #define NUM_MSG_SEQUENCES   1
 const char *TEST_CALLBACK_TEXT = "callback_text";
 
 #define NUM_MSG_SEQUENCES   1
-#define LISTVIEW_SEQ_INDEX  0
+#define TREEVIEW_SEQ_INDEX  0
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
 
 static struct msg_sequence *MsgSequences[NUM_MSG_SEQUENCES];
 
 static const struct message FillRootSeq[] = {
     { TVM_INSERTITEM, sent },
 
 static struct msg_sequence *MsgSequences[NUM_MSG_SEQUENCES];
 
 static const struct message FillRootSeq[] = {
     { TVM_INSERTITEM, sent },
-    { TVM_GETITEM, sent },
     { TVM_INSERTITEM, sent },
     { 0 }
 };
 
     { 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 },
+static const struct message rootnone_select_seq[] = {
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
     { 0 }
 };
 
     { 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 },
+static const struct message rootchild_select_seq[] = {
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    { TVM_SELECTITEM, sent|wparam, 9 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message DoTest3Seq[] = {
+static const struct message getitemtext_seq[] = {
     { TVM_INSERTITEM, sent },
     { TVM_GETITEM, sent },
     { TVM_DELETEITEM, sent },
     { 0 }
 };
 
     { TVM_INSERTITEM, sent },
     { TVM_GETITEM, sent },
     { TVM_DELETEITEM, sent },
     { 0 }
 };
 
-static const struct message DoFocusTestSeq[] = {
+static const struct message focus_seq[] = {
     { TVM_INSERTITEM, sent },
     { TVM_INSERTITEM, sent },
     { TVM_INSERTITEM, sent },
     { TVM_INSERTITEM, sent },
+    { TVM_SELECTITEM, sent|wparam, 9 },
+    /* The following end up out of order in wine */
     { WM_WINDOWPOSCHANGING, sent|defwinproc },
     { WM_WINDOWPOSCHANGING, sent|defwinproc },
-    { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 },
+    { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
     { WM_WINDOWPOSCHANGED, sent|defwinproc },
     { WM_SIZE, sent|defwinproc },
     { 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|optional },
-    { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 0x00000001 },
-    { WM_WINDOWPOSCHANGED, sent|defwinproc|optional },
-    { WM_SIZE, sent|defwinproc|optional },
-    { TVM_SELECTITEM, sent|wparam, 0x00000009 },
-    /* The following end up out of order in wine */
     { WM_PAINT, sent|defwinproc },
     { WM_PAINT, sent|defwinproc },
-    { WM_NCPAINT, sent|wparam|defwinproc, 0x00000001 },
+    { WM_NCPAINT, sent|wparam|defwinproc, 1 },
     { WM_ERASEBKGND, sent|defwinproc },
     { TVM_EDITLABEL, sent },
     { 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_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
+    { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
+    { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
     { WM_KILLFOCUS, sent|defwinproc },
     { WM_PAINT, sent|defwinproc },
     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
     { 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_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
+    { WM_ERASEBKGND, sent|defwinproc|optional },
     { WM_CTLCOLOREDIT, sent|defwinproc|optional },
     { WM_CTLCOLOREDIT, sent|defwinproc|optional },
     { 0 }
 };
 
     { 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, -1 },
+static const struct message test_get_set_bkcolor_seq[] = {
+    { TVM_GETBKCOLOR, sent|wparam|lparam, 00 },
+    { TVM_SETBKCOLOR, sent|wparam|lparam, 00 },
+    { TVM_GETBKCOLOR, sent|wparam|lparam, 00 },
+    { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
+    { TVM_GETBKCOLOR, sent|wparam|lparam, 00 },
+    { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message TestGetSetImageListSeq[] = {
-    { TVM_SETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 },
-    { TVM_GETIMAGELIST, sent|wparam|lparam, 0x00000000, 0x00000000 },
+static const struct message test_get_set_imagelist_seq[] = {
+    { TVM_SETIMAGELIST, sent|wparam|lparam, 00 },
+    { TVM_GETIMAGELIST, sent|wparam|lparam, 00 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message TestGetSetIndentSeq[] = {
-    { TVM_SETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 },
-    { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+static const struct message test_get_set_indent_seq[] = {
+    { TVM_SETINDENT, sent|wparam|lparam, 00 },
+    { TVM_GETINDENT, sent|wparam|lparam, 00 },
     /* The actual amount to indent is dependent on the system for this message */
     { TVM_SETINDENT, sent },
     /* The actual amount to indent is dependent on the system for this message */
     { TVM_SETINDENT, sent },
-    { TVM_GETINDENT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+    { TVM_GETINDENT, sent|wparam|lparam, 00 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message TestGetSetInsertMarkColorSeq[] = {
-    { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
-    { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 },
+static const struct message test_get_set_insertmarkcolor_seq[] = {
+    { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 00 },
+    { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 00 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message TestGetSetItemSeq[] = {
+static const struct message test_get_set_item_seq[] = {
     { TVM_GETITEM, sent },
     { TVM_SETITEM, sent },
     { TVM_GETITEM, sent },
     { TVM_GETITEM, sent },
     { TVM_SETITEM, sent },
     { TVM_GETITEM, sent },
@@ -146,57 +139,53 @@ static const struct message TestGetSetItemSeq[] = {
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message TestGetSetItemHeightSeq[] = {
-    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 },
-    { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0x00000000 },
-    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 },
-    { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0x00000000 },
-    { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0x00000000, 0x00000000 },
-    { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 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 },
+static const struct message test_get_set_itemheight_seq[] = {
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
+    { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
+    { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
+    { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
+    { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
     { 0 }
 };
 
     { 0 }
 };
 
-static const struct message TestGetSetScrollTimeSeq[] = {
-    { TVM_SETSCROLLTIME, sent|wparam|lparam, 0x00000014, 0x00000000 },
-    { TVM_GETSCROLLTIME, sent|wparam|lparam, 0x00000000, 0x00000000 },
+static const struct message test_get_set_scrolltime_seq[] = {
+    { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
+    { TVM_GETSCROLLTIME, sent|wparam|lparam, 00 },
     { 0 }
 };
 
     { 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, -1 },
+static const struct message test_get_set_textcolor_seq[] = {
+    { TVM_GETTEXTCOLOR, sent|wparam|lparam, 00 },
+    { TVM_SETTEXTCOLOR, sent|wparam|lparam, 00 },
+    { TVM_GETTEXTCOLOR, sent|wparam|lparam, 00 },
+    { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) },
+    { TVM_GETTEXTCOLOR, sent|wparam|lparam, 00 },
+    { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE },
     { 0 }
 };
 
     { 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 },
+static const struct message test_get_set_tooltips_seq[] = {
+    { WM_KILLFOCUS,    sent },
+    { WM_IME_SETCONTEXT, sent|optional },
+    { WM_IME_NOTIFY, sent|optional },
+    { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
+    { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
     { 0 }
 };
 
     { 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 },
+static const struct message test_get_set_unicodeformat_seq[] = {
+    { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
+    { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 00 },
+    { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 00 },
+    { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 00 },
+    { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 00 },
     { 0 }
 };
 
 static HWND hMainWnd;
 
     { 0 }
 };
 
 static HWND hMainWnd;
 
-static HWND hTree, hEdit;
 static HTREEITEM hRoot, hChild;
 
 static int pos = 0;
 static HTREEITEM hRoot, hChild;
 
 static int pos = 0;
@@ -231,42 +220,96 @@ static void IdentifyItem(HTREEITEM hItem)
     AddItem('?');
 }
 
     AddItem('?');
 }
 
-static void FillRoot(void)
+/* 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, TREEVIEW_SEQ_INDEX, &msg);
+
+    defwndproc_counter++;
+    ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
+    defwndproc_counter--;
+
+    return ret;
+}
+
+static HWND create_treeview_control(void)
+{
+    WNDPROC pOldWndProc;
+    HWND hTree;
+
+    hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
+            TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS,
+            0, 0, 120, 100, hMainWnd, (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 hTree;
+}
+
+static void fill_tree(HWND hTree)
 {
     TVINSERTSTRUCTA ins;
 {
     TVINSERTSTRUCTA ins;
-    TVITEM tvi;
     static CHAR root[]  = "Root",
                 child[] = "Child";
 
     static CHAR root[]  = "Root",
                 child[] = "Child";
 
-    Clear();
-    AddItem('A');
     ins.hParent = TVI_ROOT;
     ins.hInsertAfter = TVI_ROOT;
     U(ins).item.mask = TVIF_TEXT;
     U(ins).item.pszText = root;
     hRoot = TreeView_InsertItem(hTree, &ins);
     ins.hParent = TVI_ROOT;
     ins.hInsertAfter = TVI_ROOT;
     U(ins).item.mask = TVIF_TEXT;
     U(ins).item.pszText = root;
     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;
     U(ins).item.mask = TVIF_TEXT;
     U(ins).item.pszText = child;
     hChild = TreeView_InsertItem(hTree, &ins);
     ins.hParent = hRoot;
     ins.hInsertAfter = TVI_FIRST;
     U(ins).item.mask = TVIF_TEXT;
     U(ins).item.pszText = child;
     hChild = TreeView_InsertItem(hTree, &ins);
+}
+
+static void test_fillroot(void)
+{
+    TVITEM tvi;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+
+    fill_tree(hTree);
+
+    Clear();
+    AddItem('A');
+    assert(hRoot);
+    AddItem('B');
     assert(hChild);
     AddItem('.');
     assert(hChild);
     AddItem('.');
-
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
     ok(!strcmp(sequence, "AB."), "Item creation\n");
     ok(!strcmp(sequence, "AB."), "Item creation\n");
+
+    /* 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);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestCallback(void)
+static void test_callback(void)
 {
     HTREEITEM hRoot;
     HTREEITEM hItem1, hItem2;
 {
     HTREEITEM hRoot;
     HTREEITEM hItem1, hItem2;
@@ -275,8 +318,13 @@ static void TestCallback(void)
     CHAR test_string[] = "Test_string";
     CHAR buf[128];
     LRESULT ret;
     CHAR test_string[] = "Test_string";
     CHAR buf[128];
     LRESULT ret;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
 
 
-    TreeView_DeleteAllItems(hTree);
+    ret = TreeView_DeleteAllItems(hTree);
+    ok(ret == TRUE, "ret\n");
     ins.hParent = TVI_ROOT;
     ins.hInsertAfter = TVI_ROOT;
     U(ins).item.mask = TVIF_TEXT;
     ins.hParent = TVI_ROOT;
     ins.hInsertAfter = TVI_ROOT;
     U(ins).item.mask = TVIF_TEXT;
@@ -301,7 +349,8 @@ static void TestCallback(void)
     assert(hItem1);
 
     tvi.hItem = hItem1;
     assert(hItem1);
 
     tvi.hItem = hItem1;
-    TreeView_GetItem(hTree, &tvi);
+    ret = TreeView_GetItem(hTree, &tvi);
+    ok(ret == TRUE, "ret\n");
     ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
         tvi.pszText, test_string);
 
     ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
         tvi.pszText, test_string);
 
@@ -310,7 +359,8 @@ static void TestCallback(void)
     ret = TreeView_SetItem(hTree, &tvi);
     ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret);
     tvi.pszText = buf;
     ret = TreeView_SetItem(hTree, &tvi);
     ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret);
     tvi.pszText = buf;
-    TreeView_GetItem(hTree, &tvi);
+    ret = TreeView_GetItem(hTree, &tvi);
+    ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
         tvi.pszText, TEST_CALLBACK_TEXT);
 
     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
         tvi.pszText, TEST_CALLBACK_TEXT);
 
@@ -319,57 +369,90 @@ static void TestCallback(void)
     assert(hItem2);
     tvi.hItem = hItem2;
     memset(buf, 0, sizeof(buf));
     assert(hItem2);
     tvi.hItem = hItem2;
     memset(buf, 0, sizeof(buf));
-    TreeView_GetItem(hTree, &tvi);
+    ret = TreeView_GetItem(hTree, &tvi);
+    ok(ret == TRUE, "Expected GetItem return TRUE, got %ld\n", ret);
     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
         tvi.pszText, TEST_CALLBACK_TEXT);
     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
         tvi.pszText, TEST_CALLBACK_TEXT);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void DoTest1(void)
+static void test_select(void)
 {
     BOOL r;
 {
     BOOL r;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    /* root-none select tests */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
     r = TreeView_SelectItem(hTree, NULL);
     r = TreeView_SelectItem(hTree, NULL);
+    expect(TRUE, r);
     Clear();
     AddItem('1');
     r = TreeView_SelectItem(hTree, hRoot);
     Clear();
     AddItem('1');
     r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
     AddItem('2');
     r = TreeView_SelectItem(hTree, hRoot);
     AddItem('2');
     r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
     AddItem('3');
     r = TreeView_SelectItem(hTree, NULL);
     AddItem('3');
     r = TreeView_SelectItem(hTree, NULL);
+    expect(TRUE, r);
     AddItem('4');
     r = TreeView_SelectItem(hTree, NULL);
     AddItem('4');
     r = TreeView_SelectItem(hTree, NULL);
+    expect(TRUE, r);
     AddItem('5');
     r = TreeView_SelectItem(hTree, hRoot);
     AddItem('5');
     r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
     AddItem('.');
     ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
     AddItem('.');
     ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
-}
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
+                "root-none select seq", FALSE);
 
 
-static void DoTest2(void)
-{
-    BOOL r;
+    /* root-child select tests */
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
     r = TreeView_SelectItem(hTree, NULL);
     r = TreeView_SelectItem(hTree, NULL);
+    expect(TRUE, r);
+
     Clear();
     AddItem('1');
     r = TreeView_SelectItem(hTree, hRoot);
     Clear();
     AddItem('1');
     r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
     AddItem('2');
     r = TreeView_SelectItem(hTree, hRoot);
     AddItem('2');
     r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
     AddItem('3');
     r = TreeView_SelectItem(hTree, hChild);
     AddItem('3');
     r = TreeView_SelectItem(hTree, hChild);
+    expect(TRUE, r);
     AddItem('4');
     r = TreeView_SelectItem(hTree, hChild);
     AddItem('4');
     r = TreeView_SelectItem(hTree, hChild);
+    expect(TRUE, r);
     AddItem('5');
     r = TreeView_SelectItem(hTree, hRoot);
     AddItem('5');
     r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
     AddItem('.');
     ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
     AddItem('.');
     ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
+                "root-child select seq", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void DoTest3(void)
+static void test_getitemtext(void)
 {
     TVINSERTSTRUCTA ins;
     HTREEITEM hChild;
     TVITEM tvi;
 {
     TVINSERTSTRUCTA ins;
     HTREEITEM hChild;
     TVITEM tvi;
+    HWND hTree;
 
 
-    int nBufferSize = 80;
     CHAR szBuffer[80] = "Blah";
     CHAR szBuffer[80] = "Blah";
+    int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* add an item without TVIF_TEXT mask and pszText == NULL */
     ins.hParent = hRoot;
 
     /* add an item without TVIF_TEXT mask and pszText == NULL */
     ins.hParent = hRoot;
@@ -389,14 +472,24 @@ static void DoTest3(void)
     SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
     ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
     ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
     SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi );
     ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
     ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void DoFocusTest(void)
+static void test_focus(void)
 {
     TVINSERTSTRUCTA ins;
     static CHAR child1[]  = "Edit",
                 child2[]  = "A really long string";
     HTREEITEM hChild1, hChild2;
 {
     TVINSERTSTRUCTA ins;
     static CHAR child1[]  = "Edit",
                 child2[]  = "A really long string";
     HTREEITEM hChild1, hChild2;
+    HWND hTree;
+    HWND hEdit;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* This test verifies that when a label is being edited, scrolling
      * the treeview does not cause the label to lose focus. To test
 
     /* This test verifies that when a label is being edited, scrolling
      * the treeview does not cause the label to lose focus. To test
@@ -416,38 +509,57 @@ static void DoFocusTest(void)
     assert(hChild2);
 
     ShowWindow(hMainWnd,SW_SHOW);
     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");
     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");
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetBkColor(void)
+static void test_get_set_bkcolor(void)
 {
     COLORREF crColor = RGB(0,0,0);
 {
     COLORREF crColor = RGB(0,0,0);
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* 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 */
 
     /* 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) );
+    SendMessage( hTree, TVM_SETBKCOLOR, 0, 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 */
     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) );
+    SendMessage( hTree, TVM_SETBKCOLOR, 0, 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 );
     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 );
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq,
+        "test get set bkcolor", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetImageList(void)
+static void test_get_set_imagelist(void)
 {
     HIMAGELIST hImageList = NULL;
 {
     HIMAGELIST hImageList = NULL;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* Test a NULL HIMAGELIST */
     SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
 
     /* Test a NULL HIMAGELIST */
     SendMessage( hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList );
@@ -455,13 +567,24 @@ static void TestGetSetImageList(void)
     ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
 
     /* TODO: Test an actual image list */
     ok(hImageList == NULL, "NULL image list, reported as 0x%p, expected 0.\n", hImageList);
 
     /* TODO: Test an actual image list */
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq,
+        "test get imagelist", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetIndent(void)
+static void test_get_set_indent(void)
 {
     int ulIndent = -1;
     int ulMinIndent = -1;
     int ulMoreThanTwiceMin = -1;
 {
     int ulIndent = -1;
     int ulMinIndent = -1;
     int ulMoreThanTwiceMin = -1;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* Finding the minimum indent */
     SendMessage( hTree, TVM_SETINDENT, 0, 0 );
 
     /* Finding the minimum indent */
     SendMessage( hTree, TVM_SETINDENT, 0, 0 );
@@ -472,21 +595,44 @@ static void TestGetSetIndent(void)
     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);
     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);
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq,
+        "test get set indent", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetInsertMarkColor(void)
+static void test_get_set_insertmark(void)
 {
     COLORREF crColor = RGB(0,0,0);
 {
     COLORREF crColor = RGB(0,0,0);
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+
     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);
     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);
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq,
+        "test get set insertmark color", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetItem(void)
+static void test_get_set_item(void)
 {
     TVITEM tviRoot = {0};
     int nBufferSize = 80;
     char szBuffer[80] = {0};
 {
     TVITEM tviRoot = {0};
     int nBufferSize = 80;
     char szBuffer[80] = {0};
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* Test the root item */
     tviRoot.hItem = hRoot;
 
     /* Test the root item */
     tviRoot.hItem = hRoot;
@@ -507,12 +653,23 @@ static void TestGetSetItem(void)
     memset(szBuffer, 0, nBufferSize);
     strncpy(szBuffer, "Root", nBufferSize);
     SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
     memset(szBuffer, 0, nBufferSize);
     strncpy(szBuffer, "Root", nBufferSize);
     SendMessage( hTree, TVM_SETITEM, 0, (LPARAM)&tviRoot );
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
+        "test get set item", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetItemHeight(void)
+static void test_get_set_itemheight(void)
 {
     int ulOldHeight = 0;
     int ulNewHeight = 0;
 {
     int ulOldHeight = 0;
     int ulNewHeight = 0;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* Assuming default height to begin with */
     ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
 
     /* Assuming default height to begin with */
     ulOldHeight = (int) SendMessage( hTree, TVM_GETITEMHEIGHT, 0, 0 );
@@ -531,42 +688,77 @@ static void TestGetSetItemHeight(void)
     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);
     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);
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq,
+        "test get set item height", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetScrollTime(void)
+static void test_get_set_scrolltime(void)
 {
     int ulExpectedTime = 20;
     int ulTime = 0;
 {
     int ulExpectedTime = 20;
     int ulTime = 0;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+
     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);
     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);
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq,
+        "test get set scroll time", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetTextColor(void)
+static void test_get_set_textcolor(void)
 {
     /* If the value is -1, the control is using the system color for the text color. */
     COLORREF crColor = RGB(0,0,0);
 {
     /* If the value is -1, the control is using the system color for the text color. */
     COLORREF crColor = RGB(0,0,0);
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
+
     crColor = (COLORREF)SendMessage( hTree, TVM_GETTEXTCOLOR, 0, 0 );
     ok(crColor == -1, "Default text color reported as 0x%.8x\n", crColor);
 
     /* Test for black text */
     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) );
+    SendMessage( hTree, TVM_SETTEXTCOLOR, 0, 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 */
     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) );
+    SendMessage( hTree, TVM_SETTEXTCOLOR, 0, 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 */
     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 );
+    SendMessage( hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE );
+
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq,
+        "test get set text color", FALSE);
+
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetToolTips(void)
+static void test_get_set_tooltips(void)
 {
     HWND hwndLastToolTip = NULL;
     HWND hPopupTreeView;
 {
     HWND hwndLastToolTip = NULL;
     HWND hPopupTreeView;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* 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);
 
     /* 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);
@@ -577,13 +769,23 @@ static void TestGetSetToolTips(void)
     hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
     ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
 
     hwndLastToolTip = (HWND)SendMessage( hTree, TVM_GETTOOLTIPS, 0, 0 );
     ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
 
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq,
+        "test get set tooltips", TRUE);
+
     /* TODO: Add a test of an actual tooltip */
     /* TODO: Add a test of an actual tooltip */
+    DestroyWindow(hTree);
 }
 
 }
 
-static void TestGetSetUnicodeFormat(void)
+static void test_get_set_unicodeformat(void)
 {
     BOOL bPreviousSetting = 0;
     BOOL bNewSetting = 0;
 {
     BOOL bPreviousSetting = 0;
     BOOL bNewSetting = 0;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
 
     /* Set to Unicode */
     bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
 
     /* Set to Unicode */
     bPreviousSetting = (BOOL)SendMessage( hTree, TVM_SETUNICODEFORMAT, 1, 0 );
@@ -596,114 +798,17 @@ static void TestGetSetUnicodeFormat(void)
     ok(bNewSetting == 0, "ANSI setting did not work.\n");
 
     /* Revert to original setting */
     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);
+    SendMessage( hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0 );
 
 
-    /* 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);
+    ok_sequence(MsgSequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq,
+        "test get set unicode format", FALSE);
 
 
-    /* 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;
+    DestroyWindow(hTree);
 }
 
 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 }
 
 static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    WNDPROC pOldWndProc;
-
     switch(msg) {
     switch(msg) {
-
-    case WM_CREATE:
-    {
-        hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
-            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;
     case WM_NOTIFY:
     {
         NMHDR *pHdr = (NMHDR *)lParam;
@@ -729,15 +834,12 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa
                 }
                 return 0;
               }
                 }
                 return 0;
               }
+            case TVN_ENDLABELEDIT: return TRUE;
             }
         }
         return 0;
     }
   
             }
         }
         return 0;
     }
   
-    case WM_SIZE:
-        MoveWindow(hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
-        break;
-      
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
     case WM_DESTROY:
         PostQuitMessage(0);
         break;
@@ -748,13 +850,17 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa
     return 0L;
 }
 
     return 0L;
 }
 
-static void TestExpandInvisible(void)
+static void test_expandinvisible(void)
 {
     static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
     TVINSERTSTRUCTA ins;
     HTREEITEM node[5];
     RECT dummyRect;
     BOOL nodeVisible;
 {
     static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
     TVINSERTSTRUCTA ins;
     HTREEITEM node[5];
     RECT dummyRect;
     BOOL nodeVisible;
+    LRESULT ret;
+    HWND hTree;
+
+    hTree = create_treeview_control();
 
     /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
      *
 
     /* The test builds the following tree and expands then node 1, while node 0 is collapsed.
      *
@@ -766,8 +872,8 @@ static void TestExpandInvisible(void)
      *
      */
 
      *
      */
 
-    TreeView_DeleteAllItems(hTree);
-
+    ret = TreeView_DeleteAllItems(hTree);
+    ok(ret == TRUE, "ret\n");
     ins.hParent = TVI_ROOT;
     ins.hInsertAfter = TVI_ROOT;
     U(ins).item.mask = TVIF_TEXT;
     ins.hParent = TVI_ROOT;
     ins.hInsertAfter = TVI_ROOT;
     U(ins).item.mask = TVIF_TEXT;
@@ -815,8 +921,121 @@ static void TestExpandInvisible(void)
     ok(!nodeVisible, "Node 3 should not be visible.\n");
     nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
     ok(!nodeVisible, "Node 4 should not be visible.\n");
     ok(!nodeVisible, "Node 3 should not be visible.\n");
     nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE);
     ok(!nodeVisible, "Node 4 should not be visible.\n");
+
+    DestroyWindow(hTree);
 }
 
 }
 
+static void test_itemedit(void)
+{
+    DWORD r;
+    HWND edit;
+    TVITEMA item;
+    CHAR buff[2];
+    HWND hTree;
+
+    hTree = create_treeview_control();
+    fill_tree(hTree);
+
+    /* try with null item */
+    edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, 0);
+    ok(!IsWindow(edit), "Expected valid handle\n");
+
+    /* trigger edit */
+    edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
+    ok(IsWindow(edit), "Expected valid handle\n");
+    /* item shouldn't be selected automatically after TVM_EDITLABEL */
+    r = SendMessage(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
+    expect(0, r);
+    /* try to cancel with wrong edit handle */
+    r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
+    expect(0, r);
+    ok(IsWindow(edit), "Expected edit control to be valid\n");
+    r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
+    expect(0, r);
+    ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
+    /* try to cancel without creating edit */
+    r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
+    expect(0, r);
+
+    /* try to cancel with wrong (not null) handle */
+    edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
+    ok(IsWindow(edit), "Expected valid handle\n");
+    r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree);
+    expect(0, r);
+    ok(IsWindow(edit), "Expected edit control to be valid\n");
+    r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
+    expect(0, r);
+
+    /* remove selection after starting edit */
+    r = TreeView_SelectItem(hTree, hRoot);
+    expect(TRUE, r);
+    edit = (HWND)SendMessage(hTree, TVM_EDITLABEL, 0, (LPARAM)hRoot);
+    ok(IsWindow(edit), "Expected valid handle\n");
+    r = TreeView_SelectItem(hTree, NULL);
+    expect(TRUE, r);
+    /* alter text */
+    strncpy(buff, "x", sizeof(buff)/sizeof(CHAR));
+    r = SendMessage(edit, WM_SETTEXT, 0, (LPARAM)buff);
+    expect(TRUE, r);
+    r = SendMessage(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
+    expect(0, r);
+    ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
+    /* check that text is saved */
+    item.mask = TVIF_TEXT;
+    item.hItem = hRoot;
+    item.pszText = buff;
+    item.cchTextMax = sizeof(buff)/sizeof(CHAR);
+    r = SendMessage(hTree, TVM_GETITEM, 0, (LPARAM)&item);
+    expect(TRUE, r);
+    ok(!strcmp("x", buff), "Expected item text to change\n");
+
+    DestroyWindow(hTree);
+}
+
+static void test_treeview_classinfo(void)
+{
+    WNDCLASSA cls;
+
+    memset(&cls, 0, sizeof(cls));
+    GetClassInfo(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
+    ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
+    ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
+    expect(0, cls.cbClsExtra);
+}
+
+static void test_get_linecolor(void)
+{
+    COLORREF clr;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+
+    /* newly created control has default color */
+    clr = (COLORREF)SendMessage(hTree, TVM_GETLINECOLOR, 0, 0);
+    if (clr == 0)
+        win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
+    else
+        expect(CLR_DEFAULT, clr);
+
+    DestroyWindow(hTree);
+}
+
+static void test_get_insertmarkcolor(void)
+{
+    COLORREF clr;
+    HWND hTree;
+
+    hTree = create_treeview_control();
+
+    /* newly created control has default color */
+    clr = (COLORREF)SendMessage(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
+    if (clr == 0)
+        win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
+    else
+        expect(CLR_DEFAULT, clr);
+
+    DestroyWindow(hTree);
+}
 
 START_TEST(treeview)
 {
 
 START_TEST(treeview)
 {
@@ -851,41 +1070,32 @@ START_TEST(treeview)
     wc.lpfnWndProc = MyWndProc;
     RegisterClassA(&wc);
 
     wc.lpfnWndProc = MyWndProc;
     RegisterClassA(&wc);
 
-
     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
 
     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
       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);
-    DoTest3();
-    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest3Seq, "DoTest3", FALSE);
-
-    flush_sequences(MsgSequences, NUM_MSG_SEQUENCES);
-    DoFocusTest();
-    ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoFocusTestSeq, "DoFocusTest", TRUE);
-
-    /* Sequences tested inside due to number */
-    TestGetSet();
-
-    /* Clears all the previous items */
-    TestCallback();
-
-    /* Clears all the previous items */
-    TestExpandInvisible();
+    ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
+    if (!hMainWnd) return;
+
+    test_fillroot();
+    test_select();
+    test_getitemtext();
+    test_focus();
+    test_get_set_bkcolor();
+    test_get_set_imagelist();
+    test_get_set_indent();
+    test_get_set_insertmark();
+    test_get_set_item();
+    test_get_set_itemheight();
+    test_get_set_scrolltime();
+    test_get_set_textcolor();
+    test_get_linecolor();
+    test_get_insertmarkcolor();
+    test_get_set_tooltips();
+    test_get_set_unicodeformat();
+    test_callback();
+    test_expandinvisible();
+    test_itemedit();
+    test_treeview_classinfo();
 
     PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
     while(GetMessageA(&msg,0,0,0)) {
 
     PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
     while(GetMessageA(&msg,0,0,0)) {
index 433c190..859b3a0 100644 (file)
 #define EDIT_SEQ_INDEX      1
 #define UPDOWN_SEQ_INDEX    2
 
 #define EDIT_SEQ_INDEX      1
 #define UPDOWN_SEQ_INDEX    2
 
-static HWND parent_wnd, edit, updown;
+#define UPDOWN_ID           0
+#define BUDDY_ID            1
 
 
-static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+static HWND parent_wnd, g_edit;
 
 
-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_QUERYNEWPALETTE,   sent|optional },
-    { 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 BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
 
 
-static const struct message add_edit_to_parent_seq[] = {
-    { WM_PARENTNOTIFY, sent|wparam, WM_CREATE },
-    { 0 }
-};
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
 static const struct message add_updown_with_edit_seq[] = {
     { WM_WINDOWPOSCHANGING, sent },
 
 static const struct message add_updown_with_edit_seq[] = {
     { WM_WINDOWPOSCHANGING, sent },
@@ -182,12 +159,8 @@ static const struct message test_updown_unicode_seq[] = {
     { 0 }
 };
 
     { 0 }
 };
 
-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},
+static const struct message test_updown_pos_nochange_seq[] = {
+    { WM_GETTEXT, sent|id, 0, 0, BUDDY_ID },
     { 0 }
 };
 
     { 0 }
 };
 
@@ -254,14 +227,9 @@ static HWND create_parent_window(void)
                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
 }
 
                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
 }
 
-struct subclass_info
-{
-    WNDPROC oldproc;
-};
-
 static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -273,43 +241,37 @@ static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam,
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
+    msg.id     = BUDDY_ID;
     add_message(sequences, EDIT_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
     add_message(sequences, EDIT_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
     return ret;
 }
 
 static HWND create_edit_control(void)
 {
     defwndproc_counter--;
     return ret;
 }
 
 static HWND create_edit_control(void)
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
+    HWND hwnd;
     RECT rect;
 
     RECT rect;
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
     GetClientRect(parent_wnd, &rect);
     GetClientRect(parent_wnd, &rect);
-    edit = CreateWindowExA(0, "EDIT", NULL, WS_CHILD | WS_BORDER | WS_VISIBLE,
+    hwnd = CreateWindowExA(0, WC_EDITA, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE,
                            0, 0, rect.right, rect.bottom,
                            parent_wnd, NULL, GetModuleHandleA(NULL), NULL);
                            0, 0, rect.right, rect.bottom,
                            parent_wnd, NULL, GetModuleHandleA(NULL), NULL);
-    if (!edit)
-    {
-        HeapFree(GetProcessHeap(), 0, info);
-        return NULL;
-    }
+    if (!hwnd) return NULL;
 
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC,
-                                            (LONG_PTR)edit_subclass_proc);
-    SetWindowLongPtrA(edit, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
+                                         (LONG_PTR)edit_subclass_proc);
+    SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
 
 
-    return edit;
+    return hwnd;
 }
 
 static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 }
 
 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);
+    WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
     static LONG defwndproc_counter = 0;
     LRESULT ret;
     struct message msg;
@@ -321,46 +283,42 @@ static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wPara
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
     if (defwndproc_counter) msg.flags |= defwinproc;
     msg.wParam = wParam;
     msg.lParam = lParam;
+    msg.id     = UPDOWN_ID;
     add_message(sequences, UPDOWN_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
     add_message(sequences, UPDOWN_SEQ_INDEX, &msg);
 
     defwndproc_counter++;
-    ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+    ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
     defwndproc_counter--;
 
     return ret;
 }
 
     defwndproc_counter--;
 
     return ret;
 }
 
-static HWND create_updown_control(void)
+static HWND create_updown_control(DWORD style, HWND buddy)
 {
 {
-    struct subclass_info *info;
+    WNDPROC oldproc;
     HWND updown;
     RECT rect;
 
     HWND updown;
     RECT rect;
 
-    info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
-    if (!info)
-        return NULL;
-
     GetClientRect(parent_wnd, &rect);
     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,
+    updown = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | style,
+                                 0, 0, rect.right, rect.bottom, parent_wnd, 1, GetModuleHandleA(NULL), buddy,
                                  100, 0, 50);
                                  100, 0, 50);
-    if (!updown)
-    {
-        HeapFree(GetProcessHeap(), 0, info);
-        return NULL;
-    }
+    if (!updown) return NULL;
 
 
-    info->oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC,
-                                            (LONG_PTR)updown_subclass_proc);
-    SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)info);
+    oldproc = (WNDPROC)SetWindowLongPtrA(updown, GWLP_WNDPROC,
+                                         (LONG_PTR)updown_subclass_proc);
+    SetWindowLongPtrA(updown, GWLP_USERDATA, (LONG_PTR)oldproc);
 
     return updown;
 }
 
 static void test_updown_pos(void)
 {
 
     return updown;
 }
 
 static void test_updown_pos(void)
 {
+    HWND updown;
     int r;
 
     int r;
 
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set Range from 0 to 100 */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set Range from 0 to 100 */
@@ -410,24 +368,63 @@ static void test_updown_pos(void)
     expect(1,HIWORD(r));
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE);
     expect(1,HIWORD(r));
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos_seq , "test updown pos", FALSE);
+
+    DestroyWindow(updown);
+
+    /* there's no attempt to update buddy Edit if text didn't change */
+    SetWindowTextA(g_edit, "50");
+    updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit);
+
+    /* test sequence only on 5.8x versions */
+    r = SendMessage(updown, UDM_GETPOS32, 0, 0);
+    if (r)
+    {
+        flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+        r = SendMessage(updown, UDM_SETPOS, 0, 50);
+        expect(50,r);
+
+        ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq,
+                    "test updown pos, no change", FALSE);
+    }
+
+    DestroyWindow(updown);
 }
 
 static void test_updown_pos32(void)
 {
 }
 
 static void test_updown_pos32(void)
 {
+    HWND updown;
     int r;
     int low, high;
 
     int r;
     int low, high;
 
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set the position to 0 to 1000 */
     SendMessage(updown, UDM_SETRANGE32, 0 , 1000 );
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set the position to 0 to 1000 */
     SendMessage(updown, UDM_SETRANGE32, 0 , 1000 );
 
+    low = high = -1;
     r = SendMessage(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high );
     r = SendMessage(updown, UDM_GETRANGE32, (WPARAM) &low , (LPARAM) &high );
+    if (low == -1)
+    {
+        win_skip("UDM_SETRANGE32/UDM_GETRANGE32 not available\n");
+        DestroyWindow(updown);
+        return;
+    }
+
     expect(0,low);
     expect(1000,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 );
+    /* Set position to 500 */
+    r = SendMessage(updown, UDM_SETPOS32, 0 , 500 );
+    if (!r)
+    {
+        win_skip("UDM_SETPOS32 and UDM_GETPOS32 need 5.80\n");
+        DestroyWindow(updown);
+        return;
+    }
+    expect(50,r);
 
     /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */
 
 
     /* Since UDM_SETBUDDYINT was not set at creation bRet will always be true as a return from UDM_GETPOS32 */
 
@@ -464,30 +461,83 @@ static void test_updown_pos32(void)
     expect(1,high);
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE);
     expect(1,high);
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_pos32_seq, "test updown pos32", FALSE);
+
+    DestroyWindow(updown);
+
+    /* there's no attempt to update buddy Edit if text didn't change */
+    SetWindowTextA(g_edit, "50");
+    updown = create_updown_control(UDS_ALIGNRIGHT | UDS_SETBUDDYINT, g_edit);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    r = SendMessage(updown, UDM_SETPOS32, 0, 50);
+    expect(50,r);
+    ok_sequence(sequences, EDIT_SEQ_INDEX, test_updown_pos_nochange_seq,
+                "test updown pos, no change", FALSE);
+
+    DestroyWindow(updown);
 }
 
 static void test_updown_buddy(void)
 {
 }
 
 static void test_updown_buddy(void)
 {
-    HWND buddyReturn;
+    HWND updown, buddyReturn, buddy;
+    WNDPROC proc;
+    DWORD style;
+
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 );
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 );
-    ok(buddyReturn == edit, "Expected edit handle\n");
+    ok(buddyReturn == g_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_SETBUDDY, (WPARAM) g_edit, 0);
+    ok(buddyReturn == g_edit, "Expected edit handle\n");
 
     buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 );
 
     buddyReturn = (HWND)SendMessage(updown, UDM_GETBUDDY, 0 , 0 );
-    ok(buddyReturn == edit, "Expected edit handle\n");
+    ok(buddyReturn == g_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);
 
     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);
+
+    DestroyWindow(updown);
+
+    buddy = create_edit_control();
+    proc  = (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC);
+
+    updown= create_updown_control(UDS_ALIGNRIGHT, buddy);
+    ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n");
+
+    style = GetWindowLongA(updown, GWL_STYLE);
+    SetWindowLongA(updown, GWL_STYLE, style | UDS_ARROWKEYS);
+    style = GetWindowLongA(updown, GWL_STYLE);
+    ok(style & UDS_ARROWKEYS, "Expected UDS_ARROWKEYS\n");
+    /* no subclass if UDS_ARROWKEYS set after creation */
+    ok(proc == (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "No subclassing expected\n");
+
+    DestroyWindow(updown);
+
+    updown= create_updown_control(UDS_ALIGNRIGHT | UDS_ARROWKEYS, buddy);
+    ok(proc != (WNDPROC)GetWindowLongPtrA(buddy, GWLP_WNDPROC), "Subclassing expected\n");
+
+    if (pSetWindowSubclass)
+    {
+        /* updown uses subclass helpers for buddy on >5.8x systems */
+        ok(GetPropA(buddy, "CC32SubclassInfo") != NULL, "Expected CC32SubclassInfo property\n");
+    }
+
+    DestroyWindow(updown);
+
+    DestroyWindow(buddy);
 }
 
 static void test_updown_base(void)
 {
 }
 
 static void test_updown_base(void)
 {
+    HWND updown;
     int r;
     int r;
+    CHAR text[10];
+
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
@@ -520,12 +570,36 @@ static void test_updown_base(void)
     expect(10,r);
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE);
     expect(10,r);
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_base_seq, "test updown base", FALSE);
+
+    DestroyWindow(updown);
+
+    /* switch base with buddy attached */
+    updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit);
+
+    r = SendMessage(updown, UDM_SETPOS, 0, 10);
+    expect(50, r);
+
+    GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
+    ok(lstrcmpA(text, "10") == 0, "Expected '10', got '%s'\n", text);
+
+    r = SendMessage(updown, UDM_SETBASE, 16, 0);
+    expect(10, r);
+
+    GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
+    /* FIXME: currently hex output isn't properly formatted, but for this
+       test only change from initial text matters */
+    ok(lstrcmpA(text, "10") != 0, "Expected '0x000A', got '%s'\n", text);
+
+    DestroyWindow(updown);
 }
 
 static void test_updown_unicode(void)
 {
 }
 
 static void test_updown_unicode(void)
 {
+    HWND updown;
     int r;
 
     int r;
 
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
+
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set it to ANSI, don't check return as we don't know previous state */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     /* Set it to ANSI, don't check return as we don't know previous state */
@@ -537,6 +611,12 @@ static void test_updown_unicode(void)
     r = SendMessage(updown, UDM_SETUNICODEFORMAT, 1 , 0);
     expect(0,r);
     r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0);
     r = SendMessage(updown, UDM_SETUNICODEFORMAT, 1 , 0);
     expect(0,r);
     r = SendMessage(updown, UDM_GETUNICODEFORMAT, 0 , 0);
+    if (!r)
+    {
+        win_skip("UDM_SETUNICODEFORMAT not available\n");
+        DestroyWindow(updown);
+        return;
+    }
     expect(1,r);
 
     /* And now set it back to ANSI */
     expect(1,r);
 
     /* And now set it back to ANSI */
@@ -546,49 +626,161 @@ static void test_updown_unicode(void)
     expect(0,r);
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE);
     expect(0,r);
 
     ok_sequence(sequences, UPDOWN_SEQ_INDEX, test_updown_unicode_seq, "test updown unicode", FALSE);
-}
 
 
+    DestroyWindow(updown);
+}
 
 
-static void test_create_updown_control(void)
+static void test_updown_create(void)
 {
     CHAR text[MAX_PATH];
 {
     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);
+    HWND updown;
+    RECT r;
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    updown = create_updown_control();
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
     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);
 
     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);
+    GetWindowTextA(g_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);
 
     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);
+    DestroyWindow(updown);
 
 
-    test_updown_pos();
-    test_updown_pos32();
-    test_updown_buddy();
-    test_updown_base();
-    test_updown_unicode();
+    /* create with zero width */
+    updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0,
+                   parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0);
+    ok(updown != NULL, "Failed to create updown control\n");
+    r.right = 0;
+    GetClientRect(updown, &r);
+    ok(r.right > 0, "Expected default width, got %d\n", r.right);
+    DestroyWindow(updown);
+    /* create with really small width */
+    updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 2, 0,
+                   parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0);
+    ok(updown != NULL, "Failed to create updown control\n");
+    r.right = 0;
+    GetClientRect(updown, &r);
+    ok(r.right != 2 && r.right > 0, "Expected default width, got %d\n", r.right);
+    DestroyWindow(updown);
+    /* create with width greater than default */
+    updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 100, 0,
+                   parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0);
+    ok(updown != NULL, "Failed to create updown control\n");
+    r.right = 0;
+    GetClientRect(updown, &r);
+    ok(r.right < 100 && r.right > 0, "Expected default width, got %d\n", r.right);
+    DestroyWindow(updown);
+    /* create with zero height, UDS_HORZ */
+    updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0,
+                   parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0);
+    ok(updown != NULL, "Failed to create updown control\n");
+    r.bottom = 0;
+    GetClientRect(updown, &r);
+    ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom);
+    DestroyWindow(updown);
+    /* create with really small height, UDS_HORZ */
+    updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 2,
+                   parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0);
+    ok(updown != NULL, "Failed to create updown control\n");
+    r.bottom = 0;
+    GetClientRect(updown, &r);
+    ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom);
+    DestroyWindow(updown);
+    /* create with height greater than default, UDS_HORZ */
+    updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 100,
+                   parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0);
+    ok(updown != NULL, "Failed to create updown control\n");
+    r.bottom = 0;
+    GetClientRect(updown, &r);
+    ok(r.bottom < 100 && r.bottom > 0, "Expected default height, got %d\n", r.bottom);
+    DestroyWindow(updown);
+}
+
+static void test_UDS_SETBUDDYINT(void)
+{
+    HWND updown;
+    DWORD style, ret;
+    CHAR text[10];
+
+    /* cleanup buddy */
+    text[0] = '\0';
+    SetWindowTextA(g_edit, text);
+
+    /* creating without UDS_SETBUDDYINT */
+    updown = create_updown_control(UDS_ALIGNRIGHT, g_edit);
+    /* try to set UDS_SETBUDDYINT after creation */
+    style = GetWindowLongA(updown, GWL_STYLE);
+    SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT);
+    style = GetWindowLongA(updown, GWL_STYLE);
+    ok(style & UDS_SETBUDDYINT, "Expected UDS_SETBUDDY to be set\n");
+    SendMessage(updown, UDM_SETPOS, 0, 20);
+    GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
+    ok(lstrlenA(text) == 0, "Expected empty string\n");
+    DestroyWindow(updown);
+
+    /* creating with UDS_SETBUDDYINT */
+    updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit);
+    GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
+    /* 50 is initial value here */
+    ok(lstrcmpA(text, "50") == 0, "Expected '50', got '%s'\n", text);
+    /* now remove style flag */
+    style = GetWindowLongA(updown, GWL_STYLE);
+    SetWindowLongA(updown, GWL_STYLE, style & ~UDS_SETBUDDYINT);
+    SendMessage(updown, UDM_SETPOS, 0, 20);
+    GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
+    ok(lstrcmpA(text, "20") == 0, "Expected '20', got '%s'\n", text);
+    /* set edit text directly, check position */
+    strcpy(text, "10");
+    SetWindowTextA(g_edit, text);
+    ret = SendMessageA(updown, UDM_GETPOS, 0, 0);
+    expect(10, ret);
+    strcpy(text, "11");
+    SetWindowTextA(g_edit, text);
+    ret = SendMessageA(updown, UDM_GETPOS, 0, 0);
+    expect(11, LOWORD(ret));
+    expect(0,  HIWORD(ret));
+    /* set to invalid value */
+    strcpy(text, "21st");
+    SetWindowTextA(g_edit, text);
+    ret = SendMessageA(updown, UDM_GETPOS, 0, 0);
+    expect(11, LOWORD(ret));
+    expect(TRUE, HIWORD(ret));
+    /* set style back */
+    style = GetWindowLongA(updown, GWL_STYLE);
+    SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT);
+    SendMessage(updown, UDM_SETPOS, 0, 30);
+    GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
+    ok(lstrcmpA(text, "30") == 0, "Expected '30', got '%s'\n", text);
+    DestroyWindow(updown);
 }
 
 START_TEST(updown)
 {
 }
 
 START_TEST(updown)
 {
+    HMODULE mod = GetModuleHandleA("comctl32.dll");
+
+    pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410);
+
     InitCommonControls();
     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
     InitCommonControls();
     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
 
-    test_create_updown_control();
+    parent_wnd = create_parent_window();
+    ok(parent_wnd != NULL, "Failed to create parent window!\n");
+    g_edit = create_edit_control();
+    ok(g_edit != NULL, "Failed to create edit control\n");
+
+    test_updown_create();
+    test_updown_pos();
+    test_updown_pos32();
+    test_updown_buddy();
+    test_updown_base();
+    test_updown_unicode();
+    test_UDS_SETBUDDYINT();
+
+    DestroyWindow(g_edit);
+    DestroyWindow(parent_wnd);
 }
 }
diff --git a/rostests/winetests/comctl32/v6util.h b/rostests/winetests/comctl32/v6util.h
new file mode 100644 (file)
index 0000000..848e95b
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Utility routines for comctl32 v6 tests
+ *
+ * Copyright 2006 Mike McCormack for CodeWeavers
+ * Copyright 2007 George Gov
+ * Copyright 2009 Owen Rudge for CodeWeavers
+ *
+ * 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
+ */
+
+#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
+
+#ifdef __i386__
+#define ARCH "x86"
+#elif defined __x86_64__
+#define ARCH "amd64"
+#else
+#define ARCH "none"
+#endif
+
+static const CHAR manifest_name[] = "cc6.manifest";
+
+static const CHAR manifest[] =
+    "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
+    "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
+    "  <assemblyIdentity\n"
+    "      type=\"win32\"\n"
+    "      name=\"Wine.ComCtl32.Tests\"\n"
+    "      version=\"1.0.0.0\"\n"
+    "      processorArchitecture=\"" ARCH "\"\n"
+    "  />\n"
+    "<description>Wine comctl32 test suite</description>\n"
+    "<dependency>\n"
+    "  <dependentAssembly>\n"
+    "    <assemblyIdentity\n"
+    "        type=\"win32\"\n"
+    "        name=\"microsoft.windows.common-controls\"\n"
+    "        version=\"6.0.0.0\"\n"
+    "        processorArchitecture=\"" ARCH "\"\n"
+    "        publicKeyToken=\"6595b64144ccf1df\"\n"
+    "        language=\"*\"\n"
+    "    />\n"
+    "</dependentAssembly>\n"
+    "</dependency>\n"
+    "</assembly>\n";
+
+static void unload_v6_module(ULONG_PTR cookie, HANDLE hCtx)
+{
+    HANDLE hKernel32;
+    BOOL (WINAPI *pDeactivateActCtx)(DWORD, ULONG_PTR);
+    VOID (WINAPI *pReleaseActCtx)(HANDLE);
+
+    hKernel32 = GetModuleHandleA("kernel32.dll");
+    pDeactivateActCtx = (void*)GetProcAddress(hKernel32, "DeactivateActCtx");
+    pReleaseActCtx = (void*)GetProcAddress(hKernel32, "ReleaseActCtx");
+    if (!pDeactivateActCtx || !pReleaseActCtx)
+    {
+        win_skip("Activation contexts unsupported\n");
+        return;
+    }
+
+    pDeactivateActCtx(0, cookie);
+    pReleaseActCtx(hCtx);
+
+    DeleteFileA(manifest_name);
+}
+
+static BOOL load_v6_module(ULONG_PTR *pcookie, HANDLE *hCtx)
+{
+    HANDLE hKernel32;
+    HANDLE (WINAPI *pCreateActCtxA)(ACTCTXA*);
+    BOOL (WINAPI *pActivateActCtx)(HANDLE, ULONG_PTR*);
+
+    ACTCTXA ctx;
+    BOOL ret;
+    HANDLE file;
+    DWORD written;
+
+    hKernel32 = GetModuleHandleA("kernel32.dll");
+    pCreateActCtxA = (void*)GetProcAddress(hKernel32, "CreateActCtxA");
+    pActivateActCtx = (void*)GetProcAddress(hKernel32, "ActivateActCtx");
+    if (!(pCreateActCtxA && pActivateActCtx))
+    {
+        win_skip("Activation contexts unsupported. No version 6 tests possible.\n");
+        return FALSE;
+    }
+
+    /* create manifest */
+    file = CreateFileA( manifest_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
+    if (file != INVALID_HANDLE_VALUE)
+    {
+        ret = (WriteFile( file, manifest, sizeof(manifest)-1, &written, NULL ) &&
+               written == sizeof(manifest)-1);
+        CloseHandle( file );
+        if (!ret)
+        {
+            DeleteFileA( manifest_name );
+            skip("Failed to fill manifest file. Skipping comctl32 V6 tests.\n");
+            return FALSE;
+        }
+        else
+            trace("created %s\n", manifest_name);
+    }
+    else
+    {
+        skip("Failed to create manifest file. Skipping comctl32 V6 tests.\n");
+        return FALSE;
+    }
+
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.cbSize = sizeof(ctx);
+    ctx.lpSource = manifest_name;
+
+    *hCtx = pCreateActCtxA(&ctx);
+    ok(*hCtx != 0, "Expected context handle\n");
+
+    ret = pActivateActCtx(*hCtx, pcookie);
+    expect(TRUE, ret);
+
+    if (!ret)
+    {
+        win_skip("A problem during context activation occurred.\n");
+        DeleteFileA(manifest_name);
+    }
+
+    return ret;
+}
+
+#undef expect
+#undef ARCH