#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 BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+
#define MAX_CHARS 100
static char *textBuffer = NULL;
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) {
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) {
- 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) {
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) {
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) {
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;
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;
+ init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
+
test_comboboxex();
test_WM_LBUTTONDOWN();
+ test_CB_GETLBTEXT();
+ test_comboboxex_subclass();
+ test_get_set_item();
cleanup();
}
<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>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>
+++ /dev/null
-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;
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, 0, 0 },
+ { DTM_SETFORMATA, sent|wparam, 0 },
{ 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[] = {
- { DTM_SETMCFONT, sent|lparam, 0, 0x00000001 },
- { DTM_GETMCFONT, sent|wparam|lparam, 0x00000000, 0x00000000 },
+ { DTM_SETMCFONT, sent|lparam, 0, 1 },
+ { DTM_GETMCFONT, sent|wparam|lparam, 0, 0 },
{ 0 }
};
static const struct message test_dtm_get_monthcal_seq[] = {
- { DTM_GETMONTHCAL, sent|wparam|lparam, 0x00000000, 0x00000000 },
+ { DTM_GETMONTHCAL, sent|wparam|lparam, 0, 0 },
{ 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[] = {
- { 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[] = {
- { 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 }
};
-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)
{
- 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;
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;
}
-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;
- info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
- if (!info)
- return NULL;
-
hWndDateTime = CreateWindowEx(0,
DATETIMEPICK_CLASS,
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;
}
-static void test_dtm_set_format(HWND hWndDateTime)
+static void test_dtm_set_format(void)
{
+ HWND hWnd;
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);
- 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);
- 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;
- r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
+ r = SendMessage(hWnd, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime);
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)
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);
+
+ 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;
+ HWND hWnd;
+
+ hWnd = create_datetime_control(DTS_SHOWNONE);
+
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
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);
- 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;
+ HWND hWnd;
+
+ hWnd = create_datetime_control(DTS_SHOWNONE);
+
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
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);
- 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)
#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];
+ 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);
- r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
+ r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
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]);
- 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 */
/* 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);
- 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]);
- r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
+ r = SendMessage(hWnd, DTM_SETRANGE, GDTR_MIN, (LPARAM)st);
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);
- 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);
- 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]);
/* 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);
- 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]);
/* 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);
- 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);
- 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 */
-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;
+ 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);
- r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+ r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
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);
/* 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);
- 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 {
- 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);
- r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
+ r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st[0]);
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 {
- 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[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*/
- 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 {
- 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 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);
- 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]);
/* 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);
- 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);
- 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;
- 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) {
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);
- 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);
- 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);
- 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);
- r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
+ r = SendMessage(hWnd, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&st);
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);
- 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);
- 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)
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();
}
#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 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 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);
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)
{
+ nMessages[op]++;
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;
}
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;
-
- ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+
+ ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
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;
}
-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;
- ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+ ok(lp == (LPVOID)0xdeadbeef, "lp=%p\n", lp);
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);
- 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;
}
INT ret, i;
PVOID p;
DWORD dw, dw2, dw3;
- HRESULT hRes;
BOOL rc;
GetSystemInfo(&si);
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());
-
+
dpa = pDPA_Create(0);
ok(dpa != NULL, "\n");
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);
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);
pDPA_DeleteAllPtrs(dpa2);
rc=CheckDPA(dpa2, 0, &dw2);
ok(rc, "dw2=0x%x\n", dw2);
+
+ pDPA_Destroy(dpa);
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)
- goto skip_stream_tests;
+ {
+ win_skip("DPA_SaveStream() not available. Skipping stream tests.\n");
+ return;
+ }
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);
+
+ ret = IStream_Release(pStm);
+ ok(!ret, "ret=%d\n", ret);
+
+ ret = IStorage_Release(pStg);
+ ok(!ret, "ret=%d\n", ret);
+
+ CoUninitialize();
}
START_TEST(dpa)
hcomctl32 = GetModuleHandleA("comctl32.dll");
- if(InitFunctionPtrs(hcomctl32))
- test_dpa();
- else
+ if(!InitFunctionPtrs(hcomctl32))
+ {
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();
}
#include <assert.h>
#include "wine/test.h"
+#include "v6util.h"
#include "msg.h"
typedef struct tagEXPECTEDNOTIFY
};
static const struct message orderArray_seq[] = {
- { HDM_GETITEMCOUNT, sent },
{ HDM_SETORDERARRAY, sent|wparam, 2 },
{ HDM_GETORDERARRAY, sent|wparam, 2 },
{ 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)
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;
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)
{
- return (LONG)SendMessage(hdex, HDM_DELETEITEM, (WPARAM)idx, 0);
+ return SendMessage(hdex, HDM_DELETEITEM, idx, 0);
}
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)
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)
ok(res == i, "Got Item Count as %d\n", res);\
}
-struct subclass_info
-{
- WNDPROC oldproc;
-};
-
static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
- struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
+ WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
LRESULT ret;
struct message msg;
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;
static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
{
- struct subclass_info *info;
+ WNDPROC oldproc;
HWND childHandle;
HDLAYOUT hlayout;
RECT rectwin;
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,
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;
}
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);
- 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);
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);
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);
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);
- todo_wine
- {
- expect(1, retVal);
- }
+ expect(1, retVal);
expect(1, hdHitTestInfo.iItem);
+ expect(HHT_ONDIVIDER, hdHitTestInfo.flags);
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);
"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);
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);
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);
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);
- 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,
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);
static void test_hdm_index_messages(HWND hParent)
{
-
HWND hChild;
int retVal;
int loopcnt;
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;
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);
- 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);
- 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,
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);
- 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);
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); \
- 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);
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;
+ ULONG_PTR ctx_cookie;
+ HANDLE hCtx;
+ HWND hwnd;
if (!init())
return;
test_header_control();
test_header_order();
+ test_hdm_orderarray();
test_customdraw();
DestroyWindow(hHeaderParentWnd);
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);
}
* 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
#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 "v6util.h"
#undef VISIBLE
} 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 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 */
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 */
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(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 */
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);
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)
{
+ ULONG_PTR ctx_cookie;
+ HANDLE hCtx;
+
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");
- desktopDC=GetDC(NULL);
hinst = GetModuleHandleA(NULL);
InitCommonControls();
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);
}
handle = CreateWindowEx(0, WC_IPADDRESS, NULL,
WS_BORDER|WS_VISIBLE, 0, 0, 0, 0,
NULL, NULL, NULL, NULL);
- assert(handle);
-
return handle;
}
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));
*
* 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
#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
-#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 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 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 }
};
{ 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_ERASEBKGND, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
+ { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
{ 0 }
};
{ 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_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 },
{ 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)
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 &&
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);
+ 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--;
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 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)
{
- 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;
msg.lParam = lParam;
msg.id = LISTVIEW_ID;
add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
+ add_message(sequences, COMBINED_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_listview_control(DWORD style)
{
- struct subclass_info *info;
+ WNDPROC oldproc;
HWND hwnd;
RECT rect;
- info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
- if (!info)
- return NULL;
-
GetClientRect(hwndparent, &rect);
hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
- WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | 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());
- 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;
}
-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;
+ 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,
- hwndparent, NULL, GetModuleHandleA(NULL), NULL);
+ parent, NULL, GetModuleHandleW(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)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)
{
- 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;
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)
{
- struct subclass_info *info;
+ WNDPROC oldproc;
HWND hwnd;
- info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
- if (!info)
- return NULL;
-
hwnd = ListView_GetHeader(hwndListview);
- info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
- (LONG_PTR)header_subclass_proc);
- SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
+ 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;
}
+/* 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;
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);
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;
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)
{
- HWND hwnd, hwndheader;
- LVCOLUMN column;
- DWORD rc;
+ HWND hwnd;
+ LVCOLUMNA column;
+ LVITEMA item;
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;
- 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 */
- 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 */
- 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;
- 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;
- 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);
- 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);
+ /* 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);
}
+
/* test setting imagelist between WM_NCCREATE and WM_CREATE */
static WNDPROC listviewWndProc;
static HIMAGELIST test_create_imagelist;
LVCOLUMNA col;
RECT rect;
WNDCLASSEX cls;
+ DWORD style;
+
cls.cbSize = sizeof(WNDCLASSEX);
ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
listviewWndProc = cls.lpfnWndProc;
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);
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,
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 */
- 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");
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)
{
- HWND hwnd, hwndheader;
+ HWND hwnd;
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);
HWND hwnd;
WNDPROC oldwndproc;
- hwnd = create_listview_control(0);
+ hwnd = create_listview_control(LVS_REPORT);
insert_column(hwnd, 0);
insert_column(hwnd, 1);
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");
- 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 */
"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));
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);
HWND hwnd;
DWORD r;
+ HDC hdc;
+ HFONT hOldFont;
+ TEXTMETRICA tm;
+ RECT rect;
+ INT height;
LVITEM item0;
LVITEM item1;
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");
+ /* 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");
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);
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");
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");
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");
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");
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 },
};
- hwnd = create_listview_control(0);
+ hwnd = create_listview_control(LVS_REPORT);
for (i=0;i<items;i++) {
insert_item(hwnd, 0);
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);
+
+ /* 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);
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);
r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
expect(1, r);
r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
-todo_wine
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);
}
HWND hwnd;
DWORD r;
LVCOLUMN col;
- RECT rect;
+ RECT rect, rect2;
+ INT arr[3];
/* 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;
- r = -1;
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 = -1;
r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
expect(2, r);
/* item = -1 means header, subitem index is 1 based */
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.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)
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 */
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;
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);
- 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 */
- 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");
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);
- 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 */
- 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");
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");
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)
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;
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;
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);
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);
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);
- 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);
+ 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_columns();
test_getorigin();
test_multiselect();
+ test_getitemrect();
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);
}
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);
#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
-struct subclass_info
-{
- WNDPROC oldproc;
-};
-
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 },
{ 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_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
{ WM_QUERYUISTATE, sent|optional },
{ WM_GETFONT, sent },
+ { WM_PARENTNOTIFY, sent },
{ 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_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 }
};
{ 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},
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 }
{ 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_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},
static void test_monthcal(void)
{
HWND hwnd;
- SYSTEMTIME st[2], st1[2];
+ SYSTEMTIME st[2], st1[2], today;
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");
+
+ /* 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];
+ 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;
+ st[1].wMilliseconds = 1200;
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(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");
- 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(st1[0].wYear != 2000, "Lover limit changed\n");
+ ok(st1[0].wYear != 2000, "Lower limit changed\n");
GetSystemTime(&st[0]);
st[0].wDay = 20;
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);
}
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;
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++;
- ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
+ ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
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;
- info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
- if (!info)
- return NULL;
-
hwnd = CreateWindowEx(0,
MONTHCAL_CLASS,
"",
- style,
+ WS_CHILD | WS_BORDER | WS_VISIBLE | style,
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;
}
/* Setter and Getters Tests */
-static void test_monthcal_color(HWND hwnd)
+static void test_monthcal_color(void)
{
int res, temp;
+ HWND hwnd;
+
+ hwnd = create_monthcal_control(0);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
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;
+ HWND hwnd;
+
+ hwnd = create_monthcal_control(0);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
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);
+
+ /* 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;
- TCHAR b[128];
+ CHAR b[128];
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 */
- 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);
/* 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;
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;
+ HWND hwnd;
+
+ hwnd = create_monthcal_control(0);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
/* 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);
- 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);
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;
- UINT res;
+ UINT res, old_res;
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));
+ 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;
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;
- 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);
- 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);
- 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);
- 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);
- 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);
- 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(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);
- 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);
- 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);
- 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);
- todo_wine {expect(MCHT_CALENDARDATEPREV, res);}
+ expect_hex(MCHT_CALENDARDATEPREV, res);
#if 0
/* (125, 115) is in active area - date from this month */
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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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. */
- 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;
- 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);
- expect(40, mchit.pt.y);
+ expect((5/2) * r.bottom / 19, mchit.pt.y);
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;
- BOOL error = FALSE;
UINT res;
+ HWND hwnd;
+ RECT r;
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);
- /* (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);
- 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);
- 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;
- memset(&st_new, 0, sizeof(SYSTEMTIME));
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);
- 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);
- 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);
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;
+ 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 */
+ memset(&st_test, 0, sizeof(st_test));
st_test.wDay = 38;
st_test.wMonth = 38;
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;
+ HWND hwnd;
+
+ hwnd = create_monthcal_control(0);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
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;
- 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.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);
- 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(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);
+
+ /* 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;
+ 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);
res = SendMessage(hwnd, MCM_GETMAXSELCOUNT, 0, 0);
expect(15, res);
+ /* test invalid value */
res = SendMessage(hwnd, MCM_SETMAXSELCOUNT, -1, 0);
- todo_wine {expect(0, res);}
+ expect(0, res);
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);
+
+ /* 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;
+ HWND hwnd;
+
+ hwnd = create_monthcal_control(0);
lstrcpyA(logfont.lfFaceName, "Arial");
memset(&logfont, 0, sizeof(logfont));
/* 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);
+ 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");
+
+ 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)
HMODULE hComctl32;
BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
INITCOMMONCONTROLSEX iccex;
- HWND hwnd, parent_wnd;
hComctl32 = GetModuleHandleA("comctl32.dll");
pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
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);
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 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)
{
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");
/* 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 */
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);
- 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);
- 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 */
/* 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");
if (!create_reg_entries())
return;
+ InitPointers();
+
test_MRUListA();
+ test_CreateMRUListLazyA();
+ test_EnumMRUList();
+ test_FindMRUData();
+ test_AddMRUData();
delete_reg_entries();
}
+++ /dev/null
-/* 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)
-{
-}
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 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__)
-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));
+}
static void test_redraw(void)
{
RECT client_rect;
+ LRESULT ret;
SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
/* 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
/* 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
#include <windows.h>
#include <commctrl.h>
+#include "resources.h"
+
#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)
{
char caption[256];
GetWindowTextA(hwnd, caption, sizeof(caption));
ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
+ sheethwnd = hwnd;
return 0;
}
}
return 0;
}
-
+
static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
LPARAM lparam)
{
return FALSE;
}
}
+ case WM_NCDESTROY:
+ ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
+ return TRUE;
+
default:
return FALSE;
}
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;
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);
}
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;
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);
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);
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;
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);
}
+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();
+ test_wiznavigation();
+ test_buttons();
}
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 && \
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);
- 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)
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");