4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/test.h"
29 #define PARENT_SEQ_INDEX 0
30 #define LISTVIEW_SEQ_INDEX 1
31 #define NUM_MSG_SEQUENCES 2
36 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
37 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
38 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
42 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
44 static const struct message create_parent_wnd_seq
[] = {
45 { WM_GETMINMAXINFO
, sent
},
46 { WM_NCCREATE
, sent
},
47 { WM_NCCALCSIZE
, sent
|wparam
, 0 },
49 { WM_SHOWWINDOW
, sent
|wparam
, 1 },
50 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
51 { WM_QUERYNEWPALETTE
, sent
|optional
},
52 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
53 { WM_WINDOWPOSCHANGED
, sent
|optional
},
54 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
55 { WM_ACTIVATEAPP
, sent
|wparam
, 1 },
56 { WM_NCACTIVATE
, sent
|wparam
, 1 },
57 { WM_ACTIVATE
, sent
|wparam
, 1 },
58 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
59 { WM_IME_NOTIFY
, sent
|defwinproc
|optional
},
60 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
61 /* Win9x adds SWP_NOZORDER below */
62 { WM_WINDOWPOSCHANGED
, sent
, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
63 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
69 static const struct message redraw_listview_seq
[] = {
70 { WM_PAINT
, sent
|id
, 0, 0, LISTVIEW_ID
},
71 { WM_PAINT
, sent
|id
, 0, 0, HEADER_ID
},
72 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
73 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
74 { WM_NOTIFY
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
75 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
76 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
80 static const struct message listview_icon_spacing_seq
[] = {
81 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(20, 30) },
82 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(25, 35) },
83 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(-1, -1) },
87 static const struct message listview_color_seq
[] = {
88 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
89 { LVM_GETBKCOLOR
, sent
},
90 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
91 { LVM_GETTEXTCOLOR
, sent
},
92 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
93 { LVM_GETTEXTBKCOLOR
, sent
},
95 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
96 { LVM_GETBKCOLOR
, sent
},
97 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
98 { LVM_GETTEXTCOLOR
, sent
},
99 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
100 { LVM_GETTEXTBKCOLOR
, sent
},
102 { LVM_SETBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
103 { LVM_GETBKCOLOR
, sent
},
104 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, CLR_NONE
},
105 { LVM_GETTEXTCOLOR
, sent
},
106 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
107 { LVM_GETTEXTBKCOLOR
, sent
},
109 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
110 { LVM_GETBKCOLOR
, sent
},
111 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
112 { LVM_GETTEXTCOLOR
, sent
},
113 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
114 { LVM_GETTEXTBKCOLOR
, sent
},
118 static const struct message listview_item_count_seq
[] = {
119 { LVM_GETITEMCOUNT
, sent
},
120 { LVM_INSERTITEM
, sent
},
121 { LVM_INSERTITEM
, sent
},
122 { LVM_INSERTITEM
, sent
},
123 { LVM_GETITEMCOUNT
, sent
},
124 { LVM_DELETEITEM
, sent
|wparam
, 2 },
125 { LVM_GETITEMCOUNT
, sent
},
126 { LVM_DELETEALLITEMS
, sent
},
127 { LVM_GETITEMCOUNT
, sent
},
128 { LVM_INSERTITEM
, sent
},
129 { LVM_INSERTITEM
, sent
},
130 { LVM_GETITEMCOUNT
, sent
},
131 { LVM_INSERTITEM
, sent
},
132 { LVM_GETITEMCOUNT
, sent
},
136 static const struct message listview_itempos_seq
[] = {
137 { LVM_INSERTITEM
, sent
},
138 { LVM_INSERTITEM
, sent
},
139 { LVM_INSERTITEM
, sent
},
140 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 1, MAKELPARAM(10,5) },
141 { LVM_GETITEMPOSITION
, sent
|wparam
, 1 },
142 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 2, MAKELPARAM(0,0) },
143 { LVM_GETITEMPOSITION
, sent
|wparam
, 2 },
144 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 0, MAKELPARAM(20,20) },
145 { LVM_GETITEMPOSITION
, sent
|wparam
, 0 },
149 static const struct message listview_ownerdata_switchto_seq
[] = {
150 { WM_STYLECHANGING
, sent
},
151 { WM_STYLECHANGED
, sent
},
160 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
162 static LONG defwndproc_counter
= 0;
166 /* log system messages, except for painting */
167 if (message
< WM_USER
&&
168 message
!= WM_PAINT
&&
169 message
!= WM_ERASEBKGND
&&
170 message
!= WM_NCPAINT
&&
171 message
!= WM_NCHITTEST
&&
172 message
!= WM_GETTEXT
&&
173 message
!= WM_GETICON
&&
174 message
!= WM_DEVICECHANGE
)
176 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
178 msg
.message
= message
;
179 msg
.flags
= sent
|wparam
|lparam
;
180 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
183 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
186 defwndproc_counter
++;
187 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
188 defwndproc_counter
--;
193 static BOOL
register_parent_wnd_class(void)
198 cls
.lpfnWndProc
= parent_wnd_proc
;
201 cls
.hInstance
= GetModuleHandleA(NULL
);
203 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
204 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
205 cls
.lpszMenuName
= NULL
;
206 cls
.lpszClassName
= "Listview test parent class";
207 return RegisterClassA(&cls
);
210 static HWND
create_parent_window(void)
212 if (!register_parent_wnd_class())
215 return CreateWindowEx(0, "Listview test parent class",
216 "Listview test parent window",
217 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
218 WS_MAXIMIZEBOX
| WS_VISIBLE
,
220 GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
223 static LRESULT WINAPI
listview_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
225 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
226 static LONG defwndproc_counter
= 0;
230 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
232 /* some debug output for style changing */
233 if ((message
== WM_STYLECHANGING
||
234 message
== WM_STYLECHANGED
) && lParam
)
236 STYLESTRUCT
*style
= (STYLESTRUCT
*)lParam
;
237 trace("\told style: 0x%08x, new style: 0x%08x\n", style
->styleOld
, style
->styleNew
);
240 msg
.message
= message
;
241 msg
.flags
= sent
|wparam
|lparam
;
242 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
245 msg
.id
= LISTVIEW_ID
;
246 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
248 defwndproc_counter
++;
249 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
250 defwndproc_counter
--;
254 static HWND
create_listview_control(DWORD style
)
256 struct subclass_info
*info
;
260 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
264 GetClientRect(hwndparent
, &rect
);
265 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
266 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| LVS_REPORT
| style
,
267 0, 0, rect
.right
, rect
.bottom
,
268 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
269 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
273 HeapFree(GetProcessHeap(), 0, info
);
277 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
278 (LONG_PTR
)listview_subclass_proc
);
279 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
284 static HWND
create_custom_listview_control(DWORD style
)
286 struct subclass_info
*info
;
290 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
294 GetClientRect(hwndparent
, &rect
);
295 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
296 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
297 0, 0, rect
.right
, rect
.bottom
,
298 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
299 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
303 HeapFree(GetProcessHeap(), 0, info
);
307 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
308 (LONG_PTR
)listview_subclass_proc
);
309 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
314 static LRESULT WINAPI
header_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
316 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
317 static LONG defwndproc_counter
= 0;
321 trace("header: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
323 msg
.message
= message
;
324 msg
.flags
= sent
|wparam
|lparam
;
325 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
329 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
331 defwndproc_counter
++;
332 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
333 defwndproc_counter
--;
337 static HWND
subclass_header(HWND hwndListview
)
339 struct subclass_info
*info
;
342 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
346 hwnd
= ListView_GetHeader(hwndListview
);
347 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
348 (LONG_PTR
)header_subclass_proc
);
349 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
354 static void test_images(void)
362 static CHAR hello
[] = "hello";
364 himl
= ImageList_Create(40, 40, 0, 4, 4);
365 ok(himl
!= NULL
, "failed to create imagelist\n");
367 hbmp
= CreateBitmap(40, 40, 1, 1, NULL
);
368 ok(hbmp
!= NULL
, "failed to create bitmap\n");
370 r
= ImageList_Add(himl
, hbmp
, 0);
371 ok(r
== 0, "should be zero\n");
373 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED
,
374 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
375 ok(hwnd
!= NULL
, "failed to create listview window\n");
377 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, 0x940);
378 ok(r
== 0, "should return zero\n");
380 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)himl
);
381 ok(r
== 0, "should return zero\n");
383 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELONG(100,50));
384 /* returns dimensions */
386 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
387 ok(r
== 0, "should be zero items\n");
389 item
.mask
= LVIF_IMAGE
| LVIF_TEXT
;
394 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
395 ok(r
== -1, "should fail\n");
398 item
.pszText
= hello
;
399 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
400 ok(r
== 0, "should not fail\n");
402 memset(&r1
, 0, sizeof r1
);
404 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r1
);
406 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
407 ok(r
== TRUE
, "should not fail\n");
410 item
.pszText
= hello
;
411 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
412 ok(r
== 0, "should not fail\n");
414 memset(&r2
, 0, sizeof r2
);
416 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r2
);
418 ok(!memcmp(&r1
, &r2
, sizeof r1
), "rectangle should be the same\n");
423 static void test_checkboxes(void)
428 static CHAR text
[] = "Text",
432 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
433 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
434 ok(hwnd
!= NULL
, "failed to create listview window\n");
436 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
437 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
438 item
.stateMask
= 0xffff;
443 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
444 ok(r
== 0, "ret %d\n", r
);
447 item
.mask
= LVIF_STATE
;
448 item
.stateMask
= 0xffff;
449 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
450 ok(item
.state
== 0xfccc, "state %x\n", item
.state
);
452 /* Don't set LVIF_STATE */
453 item
.mask
= LVIF_TEXT
;
454 item
.stateMask
= 0xffff;
459 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
460 ok(r
== 1, "ret %d\n", r
);
463 item
.mask
= LVIF_STATE
;
464 item
.stateMask
= 0xffff;
465 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
466 ok(item
.state
== 0, "state %x\n", item
.state
);
468 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
469 ok(r
== 0, "should return zero\n");
471 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
473 item
.mask
= LVIF_STATE
;
474 item
.stateMask
= 0xffff;
475 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
476 ok(item
.state
== 0x1ccc, "state %x\n", item
.state
);
478 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
480 item
.mask
= LVIF_TEXT
;
482 item
.pszText
= text2
;
483 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
484 ok(r
== 2, "ret %d\n", r
);
487 item
.mask
= LVIF_STATE
;
488 item
.stateMask
= 0xffff;
489 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
490 ok(item
.state
== 0x1000, "state %x\n", item
.state
);
492 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
494 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
495 item
.stateMask
= 0xffff;
497 item
.pszText
= text3
;
498 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
499 ok(r
== 3, "ret %d\n", r
);
502 item
.mask
= LVIF_STATE
;
503 item
.stateMask
= 0xffff;
504 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
505 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
507 /* Set an item's state to checked */
509 item
.mask
= LVIF_STATE
;
510 item
.stateMask
= 0xf000;
512 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
515 item
.mask
= LVIF_STATE
;
516 item
.stateMask
= 0xffff;
517 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
518 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
520 /* Check that only the bits we asked for are returned,
521 * and that all the others are set to zero
524 item
.mask
= LVIF_STATE
;
525 item
.stateMask
= 0xf000;
527 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
528 ok(item
.state
== 0x2000, "state %x\n", item
.state
);
530 /* Set the style again and check that doesn't change an item's state */
531 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
532 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
535 item
.mask
= LVIF_STATE
;
536 item
.stateMask
= 0xffff;
537 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
538 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
540 /* Unsetting the checkbox extended style doesn't change an item's state */
541 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, 0);
542 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
545 item
.mask
= LVIF_STATE
;
546 item
.stateMask
= 0xffff;
547 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
548 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
550 /* Now setting the style again will change an item's state */
551 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
552 ok(r
== 0, "ret %x\n", r
);
555 item
.mask
= LVIF_STATE
;
556 item
.stateMask
= 0xffff;
557 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
558 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
560 /* Toggle checkbox tests (bug 9934) */
561 memset (&item
, 0xcc, sizeof(item
));
562 item
.mask
= LVIF_STATE
;
565 item
.state
= LVIS_FOCUSED
;
566 item
.stateMask
= LVIS_FOCUSED
;
567 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
571 item
.mask
= LVIF_STATE
;
572 item
.stateMask
= 0xffff;
573 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
574 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
576 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
578 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
582 item
.mask
= LVIF_STATE
;
583 item
.stateMask
= 0xffff;
584 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
585 ok(item
.state
== 0x2aab, "state %x\n", item
.state
);
587 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
589 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
593 item
.mask
= LVIF_STATE
;
594 item
.stateMask
= 0xffff;
595 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
596 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
601 static void insert_column(HWND hwnd
, int idx
)
606 memset(&column
, 0xcc, sizeof(column
));
607 column
.mask
= LVCF_SUBITEM
;
608 column
.iSubItem
= idx
;
610 rc
= ListView_InsertColumn(hwnd
, idx
, &column
);
614 static void insert_item(HWND hwnd
, int idx
)
616 static CHAR text
[] = "foo";
621 memset(&item
, 0xcc, sizeof (item
));
622 item
.mask
= LVIF_TEXT
;
627 rc
= ListView_InsertItem(hwnd
, &item
);
631 static void test_items(void)
633 const LPARAM lparamTest
= 0x42;
637 static CHAR text
[] = "Text";
639 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
640 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
641 ok(hwnd
!= NULL
, "failed to create listview window\n");
644 * Test setting/getting item params
647 /* Set up two columns */
648 insert_column(hwnd
, 0);
649 insert_column(hwnd
, 1);
651 /* LVIS_SELECTED with zero stateMask */
653 memset (&item
, 0, sizeof (item
));
654 item
.mask
= LVIF_STATE
;
655 item
.state
= LVIS_SELECTED
;
659 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
660 ok(r
== 0, "ret %d\n", r
);
662 memset (&item
, 0xcc, sizeof (item
));
663 item
.mask
= LVIF_STATE
;
664 item
.stateMask
= LVIS_SELECTED
;
668 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
669 ok(r
!= 0, "ret %d\n", r
);
670 ok(item
.state
& LVIS_SELECTED
, "Expected LVIS_SELECTED\n");
671 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
673 /* LVIS_SELECTED with zero stateMask */
675 memset (&item
, 0, sizeof (item
));
676 item
.mask
= LVIF_STATE
;
677 item
.state
= LVIS_FOCUSED
;
681 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
682 ok(r
== 0, "ret %d\n", r
);
684 memset (&item
, 0xcc, sizeof (item
));
685 item
.mask
= LVIF_STATE
;
686 item
.stateMask
= LVIS_FOCUSED
;
690 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
691 ok(r
!= 0, "ret %d\n", r
);
692 ok(item
.state
& LVIS_FOCUSED
, "Expected LVIS_FOCUSED\n");
693 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
695 /* LVIS_CUT with LVIS_FOCUSED stateMask */
697 memset (&item
, 0, sizeof (item
));
698 item
.mask
= LVIF_STATE
;
699 item
.state
= LVIS_CUT
;
700 item
.stateMask
= LVIS_FOCUSED
;
703 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
704 ok(r
== 0, "ret %d\n", r
);
706 memset (&item
, 0xcc, sizeof (item
));
707 item
.mask
= LVIF_STATE
;
708 item
.stateMask
= LVIS_CUT
;
712 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
713 ok(r
!= 0, "ret %d\n", r
);
714 ok(item
.state
& LVIS_CUT
, "Expected LVIS_CUT\n");
715 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
717 /* Insert an item with just a param */
718 memset (&item
, 0xcc, sizeof (item
));
719 item
.mask
= LVIF_PARAM
;
722 item
.lParam
= lparamTest
;
723 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
724 ok(r
== 0, "ret %d\n", r
);
726 /* Test getting of the param */
727 memset (&item
, 0xcc, sizeof (item
));
728 item
.mask
= LVIF_PARAM
;
731 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
732 ok(r
!= 0, "ret %d\n", r
);
733 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
735 /* Set up a subitem */
736 memset (&item
, 0xcc, sizeof (item
));
737 item
.mask
= LVIF_TEXT
;
741 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
742 ok(r
!= 0, "ret %d\n", r
);
744 /* Query param from subitem: returns main item param */
745 memset (&item
, 0xcc, sizeof (item
));
746 item
.mask
= LVIF_PARAM
;
749 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
750 ok(r
!= 0, "ret %d\n", r
);
751 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
753 /* Set up param on first subitem: no effect */
754 memset (&item
, 0xcc, sizeof (item
));
755 item
.mask
= LVIF_PARAM
;
758 item
.lParam
= lparamTest
+1;
759 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
760 ok(r
== 0, "ret %d\n", r
);
762 /* Query param from subitem again: should still return main item param */
763 memset (&item
, 0xcc, sizeof (item
));
764 item
.mask
= LVIF_PARAM
;
767 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
768 ok(r
!= 0, "ret %d\n", r
);
769 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
771 /**** Some tests of state highlighting ****/
772 memset (&item
, 0xcc, sizeof (item
));
773 item
.mask
= LVIF_STATE
;
776 item
.state
= LVIS_SELECTED
;
777 item
.stateMask
= LVIS_SELECTED
| LVIS_DROPHILITED
;
778 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
779 ok(r
!= 0, "ret %d\n", r
);
781 item
.state
= LVIS_DROPHILITED
;
782 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
783 ok(r
!= 0, "ret %d\n", r
);
785 memset (&item
, 0xcc, sizeof (item
));
786 item
.mask
= LVIF_STATE
;
790 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
791 ok(r
!= 0, "ret %d\n", r
);
792 ok(item
.state
== LVIS_SELECTED
, "got state %x, expected %x\n", item
.state
, LVIS_SELECTED
);
794 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
795 ok(r
!= 0, "ret %d\n", r
);
796 todo_wine
ok(item
.state
== LVIS_DROPHILITED
, "got state %x, expected %x\n", item
.state
, LVIS_DROPHILITED
);
801 static void test_columns(void)
807 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
808 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
809 ok(hwnd
!= NULL
, "failed to create listview window\n");
811 /* Add a column with no mask */
812 memset(&column
, 0xcc, sizeof(column
));
814 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
815 ok(rc
==0, "Inserting column with no mask failed with %d\n", rc
);
817 /* Check its width */
818 rc
= ListView_GetColumnWidth(hwnd
, 0);
820 broken(rc
==0), /* win9x */
821 "Inserting column with no mask failed to set width to 10 with %d\n", rc
);
825 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
826 static WNDPROC listviewWndProc
;
827 static HIMAGELIST test_create_imagelist
;
829 static LRESULT CALLBACK
create_test_wndproc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
833 if (uMsg
== WM_CREATE
)
835 LPCREATESTRUCT lpcs
= (LPCREATESTRUCT
)lParam
;
836 lpcs
->style
|= LVS_REPORT
;
838 ret
= CallWindowProc(listviewWndProc
, hwnd
, uMsg
, wParam
, lParam
);
839 if (uMsg
== WM_CREATE
) SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)test_create_imagelist
);
843 static void test_create(void)
851 cls
.cbSize
= sizeof(WNDCLASSEX
);
852 ok(GetClassInfoEx(GetModuleHandle(NULL
), "SysListView32", &cls
), "GetClassInfoEx failed\n");
853 listviewWndProc
= cls
.lpfnWndProc
;
854 cls
.lpfnWndProc
= create_test_wndproc
;
855 cls
.lpszClassName
= "MyListView32";
856 ok(RegisterClassEx(&cls
), "RegisterClassEx failed\n");
858 test_create_imagelist
= ImageList_Create(16, 16, 0, 5, 10);
859 hList
= CreateWindow("MyListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
860 ok((HIMAGELIST
)SendMessage(hList
, LVM_GETIMAGELIST
, 0, 0) == test_create_imagelist
, "Image list not obtained\n");
861 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
862 ok(IsWindow(hHeader
) && IsWindowVisible(hHeader
), "Listview not in report mode\n");
863 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
864 DestroyWindow(hList
);
866 /* header isn't created on LVS_ICON and LVS_LIST styles */
867 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
868 GetModuleHandle(NULL
), 0);
869 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
870 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
871 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
873 memset(&col
, 0, sizeof(LVCOLUMNA
));
874 col
.mask
= LVCF_WIDTH
;
876 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
877 ok(r
== 0, "Expected 0 column's inserted\n");
878 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
879 ok(IsWindow(hHeader
), "Header should be created\n");
880 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
881 DestroyWindow(hList
);
883 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
884 GetModuleHandle(NULL
), 0);
885 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
886 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
887 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
889 memset(&col
, 0, sizeof(LVCOLUMNA
));
890 col
.mask
= LVCF_WIDTH
;
892 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
893 ok(r
== 0, "Expected 0 column's inserted\n");
894 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
895 ok(IsWindow(hHeader
), "Header should be created\n");
896 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
897 DestroyWindow(hList
);
899 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
900 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
901 GetModuleHandle(NULL
), 0);
902 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLongPtr(hList
, GWL_STYLE
) | LVS_REPORT
);
903 ok(ret
& WS_VISIBLE
, "Style wrong, should have WS_VISIBLE\n");
904 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
905 ok(IsWindow(hHeader
), "Header should be created\n");
906 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLong(hList
, GWL_STYLE
) & ~LVS_REPORT
);
907 ok((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
908 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
909 ok(IsWindow(hHeader
), "Header should be created\n");
910 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
911 DestroyWindow(hList
);
913 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
914 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
915 GetModuleHandle(NULL
), 0);
916 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
917 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_LIST
) | LVS_REPORT
);
918 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_LIST
)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
919 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
920 ok(IsWindow(hHeader
), "Header should be created\n");
921 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
922 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
923 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_REPORT
) | LVS_LIST
);
924 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
925 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
926 ok(IsWindow(hHeader
), "Header should be created\n");
927 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
928 DestroyWindow(hList
);
930 /* LVS_REPORT without WS_VISIBLE */
931 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
932 GetModuleHandle(NULL
), 0);
933 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
934 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
935 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
937 memset(&col
, 0, sizeof(LVCOLUMNA
));
938 col
.mask
= LVCF_WIDTH
;
940 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
941 ok(r
== 0, "Expected 0 column's inserted\n");
942 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
943 ok(IsWindow(hHeader
), "Header should be created\n");
944 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
945 DestroyWindow(hList
);
947 /* LVS_REPORT without WS_VISIBLE, try to show it */
948 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
949 GetModuleHandle(NULL
), 0);
950 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
951 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
952 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
953 ShowWindow(hList
, SW_SHOW
);
954 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
955 ok(IsWindow(hHeader
), "Header should be created\n");
956 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
957 DestroyWindow(hList
);
959 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
960 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
|LVS_NOCOLUMNHEADER
|WS_VISIBLE
,
961 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
962 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
963 ok(IsWindow(hHeader
), "Header should be created\n");
964 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
965 /* HDS_DRAGDROP set by default */
966 ok(GetWindowLongPtr(hHeader
, GWL_STYLE
) & HDS_DRAGDROP
, "Expected header to have HDS_DRAGDROP\n");
967 DestroyWindow(hList
);
969 /* setting LVS_EX_HEADERDRAGDROP creates header */
970 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
971 GetModuleHandle(NULL
), 0);
972 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
973 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
974 SendMessage(hList
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_HEADERDRAGDROP
);
975 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
976 ok(IsWindow(hHeader
), "Header should be created\n");
977 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
978 DestroyWindow(hList
);
981 static void test_redraw(void)
983 HWND hwnd
, hwndheader
;
985 hwnd
= create_listview_control(0);
986 hwndheader
= subclass_header(hwnd
);
988 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
990 trace("invalidate & update\n");
991 InvalidateRect(hwnd
, NULL
, TRUE
);
993 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, redraw_listview_seq
, "redraw listview", FALSE
);
995 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1000 static LRESULT WINAPI
cd_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1002 COLORREF clr
, c0ffee
= RGB(0xc0, 0xff, 0xee);
1004 if(msg
== WM_NOTIFY
) {
1005 NMHDR
*nmhdr
= (PVOID
)lp
;
1006 if(nmhdr
->code
== NM_CUSTOMDRAW
) {
1007 NMLVCUSTOMDRAW
*nmlvcd
= (PVOID
)nmhdr
;
1008 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd
->nmcd
.dwDrawStage
);
1009 switch(nmlvcd
->nmcd
.dwDrawStage
) {
1011 SetBkColor(nmlvcd
->nmcd
.hdc
, c0ffee
);
1012 return CDRF_NOTIFYITEMDRAW
;
1013 case CDDS_ITEMPREPAINT
:
1014 nmlvcd
->clrTextBk
= CLR_DEFAULT
;
1015 return CDRF_NOTIFYSUBITEMDRAW
;
1016 case CDDS_ITEMPREPAINT
| CDDS_SUBITEM
:
1017 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1018 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1019 return CDRF_NOTIFYPOSTPAINT
;
1020 case CDDS_ITEMPOSTPAINT
| CDDS_SUBITEM
:
1021 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1022 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1023 return CDRF_DODEFAULT
;
1025 return CDRF_DODEFAULT
;
1029 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
1032 static void test_customdraw(void)
1037 hwnd
= create_listview_control(0);
1039 insert_column(hwnd
, 0);
1040 insert_column(hwnd
, 1);
1041 insert_item(hwnd
, 0);
1043 oldwndproc
= (WNDPROC
)SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
,
1044 (LONG_PTR
)cd_wndproc
);
1046 InvalidateRect(hwnd
, NULL
, TRUE
);
1049 SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
, (LONG_PTR
)oldwndproc
);
1051 DestroyWindow(hwnd
);
1054 static void test_icon_spacing(void)
1056 /* LVM_SETICONSPACING */
1057 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1063 hwnd
= create_custom_listview_control(LVS_ICON
);
1064 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1066 r
= SendMessage(hwnd
, WM_NOTIFYFORMAT
, (WPARAM
)hwndparent
, (LPARAM
)NF_REQUERY
);
1067 expect(NFR_ANSI
, r
);
1069 /* reset the icon spacing to defaults */
1070 SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1072 /* now we can request what the defaults are */
1073 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1077 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1079 trace("test icon spacing\n");
1081 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(20, 30));
1082 ok(r
== MAKELONG(w
, h
) ||
1083 broken(r
== MAKELONG(w
, w
)), /* win98 */
1084 "Expected %d, got %d\n", MAKELONG(w
, h
), r
);
1086 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(25, 35));
1087 expect(MAKELONG(20,30), r
);
1089 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1,-1));
1090 expect(MAKELONG(25,35), r
);
1092 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_icon_spacing_seq
, "test icon spacing seq", FALSE
);
1094 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1095 DestroyWindow(hwnd
);
1098 static void test_color(void)
1100 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1107 COLORREF colors
[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE
, RGB(255,255,255)};
1109 hwnd
= create_listview_control(0);
1110 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1112 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1114 trace("test color seq\n");
1115 for (i
= 0; i
< 4; i
++)
1119 r
= SendMessage(hwnd
, LVM_SETBKCOLOR
, 0, color
);
1121 r
= SendMessage(hwnd
, LVM_GETBKCOLOR
, 0, color
);
1124 r
= SendMessage(hwnd
, LVM_SETTEXTCOLOR
, 0, color
);
1126 r
= SendMessage(hwnd
, LVM_GETTEXTCOLOR
, 0, color
);
1129 r
= SendMessage(hwnd
, LVM_SETTEXTBKCOLOR
, 0, color
);
1131 r
= SendMessage(hwnd
, LVM_GETTEXTBKCOLOR
, 0, color
);
1135 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_color_seq
, "test color seq", FALSE
);
1137 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1138 DestroyWindow(hwnd
);
1141 static void test_item_count(void)
1143 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1151 static CHAR item0text
[] = "item0";
1152 static CHAR item1text
[] = "item1";
1153 static CHAR item2text
[] = "item2";
1155 hwnd
= create_listview_control(0);
1156 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1158 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1160 trace("test item count\n");
1162 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1166 item0
.mask
= LVIF_TEXT
;
1169 item0
.pszText
= item0text
;
1170 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1173 /* [item0, item1] */
1174 item1
.mask
= LVIF_TEXT
;
1177 item1
.pszText
= item1text
;
1178 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1181 /* [item0, item1, item2] */
1182 item2
.mask
= LVIF_TEXT
;
1185 item2
.pszText
= item2text
;
1186 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1189 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1192 /* [item0, item1] */
1193 r
= SendMessage(hwnd
, LVM_DELETEITEM
, 2, 0);
1196 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1200 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
1203 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1207 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1210 /* [item0, item1] */
1211 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1214 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1217 /* [item0, item1, item2] */
1218 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1221 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1224 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_item_count_seq
, "test item count seq", FALSE
);
1226 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1227 DestroyWindow(hwnd
);
1230 static void test_item_position(void)
1232 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1241 static CHAR item0text
[] = "item0";
1242 static CHAR item1text
[] = "item1";
1243 static CHAR item2text
[] = "item2";
1245 hwnd
= create_custom_listview_control(LVS_ICON
);
1246 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1248 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1250 trace("test item position\n");
1253 item0
.mask
= LVIF_TEXT
;
1256 item0
.pszText
= item0text
;
1257 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1260 /* [item0, item1] */
1261 item1
.mask
= LVIF_TEXT
;
1264 item1
.pszText
= item1text
;
1265 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1268 /* [item0, item1, item2] */
1269 item2
.mask
= LVIF_TEXT
;
1272 item2
.pszText
= item2text
;
1273 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1276 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 1, MAKELPARAM(10,5));
1278 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 1, (LPARAM
) &position
);
1280 expect2(10, 5, position
.x
, position
.y
);
1282 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 2, MAKELPARAM(0,0));
1284 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 2, (LPARAM
) &position
);
1286 expect2(0, 0, position
.x
, position
.y
);
1288 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 0, MAKELPARAM(20,20));
1290 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
) &position
);
1292 expect2(20, 20, position
.x
, position
.y
);
1294 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_itempos_seq
, "test item position seq", TRUE
);
1296 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1297 DestroyWindow(hwnd
);
1300 static void test_getorigin(void)
1308 position
.x
= position
.y
= 0;
1310 hwnd
= create_custom_listview_control(LVS_ICON
);
1311 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1312 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1313 trace("test get origin results\n");
1314 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1316 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1317 DestroyWindow(hwnd
);
1319 hwnd
= create_custom_listview_control(LVS_SMALLICON
);
1320 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1321 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1322 trace("test get origin results\n");
1323 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1325 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1326 DestroyWindow(hwnd
);
1328 hwnd
= create_custom_listview_control(LVS_LIST
);
1329 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1330 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1331 trace("test get origin results\n");
1332 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1334 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1335 DestroyWindow(hwnd
);
1337 hwnd
= create_custom_listview_control(LVS_REPORT
);
1338 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1339 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1340 trace("test get origin results\n");
1341 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1343 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1344 DestroyWindow(hwnd
);
1348 static void test_multiselect(void)
1350 typedef struct t_select_task
1361 int i
,j
,item_count
,selected_count
;
1362 static const int items
=5;
1367 static struct t_select_task task_list
[] = {
1368 { "using VK_DOWN", 0, VK_DOWN
, -1, -1 },
1369 { "using VK_UP", -1, VK_UP
, -1, -1 },
1370 { "using VK_END", 0, VK_END
, 1, -1 },
1371 { "using VK_HOME", -1, VK_HOME
, 1, -1 }
1375 hwnd
= create_listview_control(0);
1377 for (i
=0;i
<items
;i
++) {
1378 insert_item(hwnd
, 0);
1381 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1383 expect(items
,item_count
);
1386 task
= task_list
[i
];
1388 /* deselect all items */
1389 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1390 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1392 /* set initial position */
1393 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, (task
.initPos
== -1 ? item_count
-1 : task
.initPos
));
1394 ListView_SetItemState(hwnd
,(task
.initPos
== -1 ? item_count
-1 : task
.initPos
),LVIS_SELECTED
,LVIS_SELECTED
);
1396 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1398 ok(selected_count
== 1, "There should be only one selected item at the beginning (is %d)\n",selected_count
);
1400 /* Set SHIFT key pressed */
1401 GetKeyboardState(kstate
);
1402 kstate
[VK_SHIFT
]=0x80;
1403 SetKeyboardState(kstate
);
1405 for (j
=1;j
<=(task
.count
== -1 ? item_count
: task
.count
);j
++) {
1406 r
= SendMessage(hwnd
, WM_KEYDOWN
, task
.loopVK
, 0);
1408 r
= SendMessage(hwnd
, WM_KEYUP
, task
.loopVK
, 0);
1412 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1414 ok((task
.result
== -1 ? item_count
: task
.result
) == selected_count
, "Failed multiple selection %s. There should be %d selected items (is %d)\n", task
.descr
, item_count
, selected_count
);
1416 /* Set SHIFT key released */
1417 GetKeyboardState(kstate
);
1418 kstate
[VK_SHIFT
]=0x00;
1419 SetKeyboardState(kstate
);
1421 DestroyWindow(hwnd
);
1423 /* make multiple selection, then switch to LVS_SINGLESEL */
1424 hwnd
= create_listview_control(0);
1425 for (i
=0;i
<items
;i
++) {
1426 insert_item(hwnd
, 0);
1428 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1429 expect(items
,item_count
);
1430 /* deselect all items */
1431 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1432 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1434 ListView_SetItemState(hwnd
, i
, LVIS_SELECTED
, LVIS_SELECTED
);
1437 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1439 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1443 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1444 ok(!(style
& LVS_SINGLESEL
), "LVS_SINGLESEL isn't expected\n");
1445 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SINGLESEL
);
1446 /* check that style is accepted */
1447 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1448 ok(style
& LVS_SINGLESEL
, "LVS_SINGLESEL expected\n");
1451 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1452 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1454 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1456 SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1459 /* select one more */
1460 ListView_SetItemState(hwnd
, 3, LVIS_SELECTED
, LVIS_SELECTED
);
1463 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1464 ok(!(r
& LVIS_SELECTED
), "Expected item %d to be unselected\n", i
);
1466 r
= ListView_GetItemState(hwnd
, 3, LVIS_SELECTED
);
1467 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1469 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1471 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1475 DestroyWindow(hwnd
);
1478 static void test_subitem_rect(void)
1485 /* test LVM_GETSUBITEMRECT for header */
1486 hwnd
= create_listview_control(0);
1487 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1488 /* add some columns */
1489 memset(&col
, 0, sizeof(LVCOLUMN
));
1490 col
.mask
= LVCF_WIDTH
;
1493 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1497 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 1, (LPARAM
)&col
);
1501 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 2, (LPARAM
)&col
);
1503 /* item = -1 means header, subitem index is 1 based */
1504 rect
.left
= LVIR_BOUNDS
;
1506 rect
.right
= rect
.bottom
= 0;
1507 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1510 rect
.left
= LVIR_BOUNDS
;
1512 rect
.right
= rect
.bottom
= 0;
1513 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1515 ok(r
!= 0, "Expected not-null LRESULT\n");
1516 expect(100, rect
.left
);
1517 expect(250, rect
.right
);
1518 expect(3, rect
.top
);
1520 rect
.left
= LVIR_BOUNDS
;
1522 rect
.right
= rect
.bottom
= 0;
1523 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1525 ok(r
!= 0, "Expected not-null LRESULT\n");
1526 expect(250, rect
.left
);
1527 expect(450, rect
.right
);
1528 expect(3, rect
.top
);
1531 DestroyWindow(hwnd
);
1534 /* comparison callback for test_sorting */
1535 static INT WINAPI
test_CallBackCompare(LPARAM first
, LPARAM second
, LPARAM lParam
)
1537 if (first
== second
) return 0;
1538 return (first
> second
? 1 : -1);
1541 static void test_sorting(void)
1547 hwnd
= create_listview_control(0);
1548 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1550 /* insert some items */
1551 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
1552 item
.state
= LVIS_SELECTED
;
1556 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1559 item
.mask
= LVIF_PARAM
;
1563 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1566 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
1567 item
.state
= LVIS_SELECTED
;
1571 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1574 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1577 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1580 r
= SendMessage(hwnd
, LVM_SORTITEMS
, 0, (LPARAM
)test_CallBackCompare
);
1583 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1585 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1587 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 0, LVIS_SELECTED
);
1589 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 1, LVIS_SELECTED
);
1590 expect(LVIS_SELECTED
, r
);
1591 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 2, LVIS_SELECTED
);
1592 expect(LVIS_SELECTED
, r
);
1594 DestroyWindow(hwnd
);
1597 static void test_ownerdata(void)
1600 LONG_PTR style
, ret
;
1604 /* it isn't possible to set LVS_OWNERDATA after creation */
1605 hwnd
= create_listview_control(0);
1606 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1607 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1608 ok(!(style
& LVS_OWNERDATA
) && style
, "LVS_OWNERDATA isn't expected\n");
1610 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1612 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1613 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1614 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1615 "try to switch to LVS_OWNERDATA seq", FALSE
);
1617 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1618 ok(!(style
& LVS_OWNERDATA
), "LVS_OWNERDATA isn't expected\n");
1619 DestroyWindow(hwnd
);
1621 /* try to set LVS_OWNERDATA after creation just having it */
1622 hwnd
= create_listview_control(LVS_OWNERDATA
);
1623 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1624 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1625 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1627 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1629 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1630 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1631 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1632 "try to switch to LVS_OWNERDATA seq", FALSE
);
1633 DestroyWindow(hwnd
);
1635 /* try to remove LVS_OWNERDATA after creation just having it */
1636 hwnd
= create_listview_control(LVS_OWNERDATA
);
1637 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1638 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1639 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1641 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1643 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
& ~LVS_OWNERDATA
);
1644 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1645 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1646 "try to switch to LVS_OWNERDATA seq", FALSE
);
1647 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1648 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1649 DestroyWindow(hwnd
);
1651 /* try select an item */
1652 hwnd
= create_listview_control(LVS_OWNERDATA
);
1653 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1654 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1655 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1656 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1658 memset(&item
, 0, sizeof(item
));
1659 item
.stateMask
= LVIS_SELECTED
;
1660 item
.state
= LVIS_SELECTED
;
1661 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
1663 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1665 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1667 DestroyWindow(hwnd
);
1669 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
1670 hwnd
= create_listview_control(LVS_OWNERDATA
);
1671 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1672 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1673 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1674 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1676 memset(&item
, 0, sizeof(item
));
1677 item
.mask
= LVIF_STATE
;
1679 item
.stateMask
= LVIS_SELECTED
;
1680 item
.state
= LVIS_SELECTED
;
1681 res
= SendMessageA(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
1683 DestroyWindow(hwnd
);
1686 START_TEST(listview
)
1689 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
1691 hComctl32
= GetModuleHandleA("comctl32.dll");
1692 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
1693 if (pInitCommonControlsEx
)
1695 INITCOMMONCONTROLSEX iccex
;
1696 iccex
.dwSize
= sizeof(iccex
);
1697 iccex
.dwICC
= ICC_LISTVIEW_CLASSES
;
1698 pInitCommonControlsEx(&iccex
);
1701 InitCommonControls();
1703 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1705 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1706 hwndparent
= create_parent_window();
1707 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent window", TRUE
);
1708 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1716 test_icon_spacing();
1719 test_item_position();
1723 test_subitem_rect();