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
);
970 static void test_redraw(void)
972 HWND hwnd
, hwndheader
;
974 hwnd
= create_listview_control(0);
975 hwndheader
= subclass_header(hwnd
);
977 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
979 trace("invalidate & update\n");
980 InvalidateRect(hwnd
, NULL
, TRUE
);
982 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, redraw_listview_seq
, "redraw listview", FALSE
);
984 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
989 static LRESULT WINAPI
cd_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
991 COLORREF clr
, c0ffee
= RGB(0xc0, 0xff, 0xee);
993 if(msg
== WM_NOTIFY
) {
994 NMHDR
*nmhdr
= (PVOID
)lp
;
995 if(nmhdr
->code
== NM_CUSTOMDRAW
) {
996 NMLVCUSTOMDRAW
*nmlvcd
= (PVOID
)nmhdr
;
997 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd
->nmcd
.dwDrawStage
);
998 switch(nmlvcd
->nmcd
.dwDrawStage
) {
1000 SetBkColor(nmlvcd
->nmcd
.hdc
, c0ffee
);
1001 return CDRF_NOTIFYITEMDRAW
;
1002 case CDDS_ITEMPREPAINT
:
1003 nmlvcd
->clrTextBk
= CLR_DEFAULT
;
1004 return CDRF_NOTIFYSUBITEMDRAW
;
1005 case CDDS_ITEMPREPAINT
| CDDS_SUBITEM
:
1006 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1007 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1008 return CDRF_NOTIFYPOSTPAINT
;
1009 case CDDS_ITEMPOSTPAINT
| CDDS_SUBITEM
:
1010 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1011 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1012 return CDRF_DODEFAULT
;
1014 return CDRF_DODEFAULT
;
1018 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
1021 static void test_customdraw(void)
1026 hwnd
= create_listview_control(0);
1028 insert_column(hwnd
, 0);
1029 insert_column(hwnd
, 1);
1030 insert_item(hwnd
, 0);
1032 oldwndproc
= (WNDPROC
)SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
,
1033 (LONG_PTR
)cd_wndproc
);
1035 InvalidateRect(hwnd
, NULL
, TRUE
);
1038 SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
, (LONG_PTR
)oldwndproc
);
1040 DestroyWindow(hwnd
);
1043 static void test_icon_spacing(void)
1045 /* LVM_SETICONSPACING */
1046 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1052 hwnd
= create_custom_listview_control(LVS_ICON
);
1053 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1055 r
= SendMessage(hwnd
, WM_NOTIFYFORMAT
, (WPARAM
)hwndparent
, (LPARAM
)NF_REQUERY
);
1056 expect(NFR_ANSI
, r
);
1058 /* reset the icon spacing to defaults */
1059 SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1061 /* now we can request what the defaults are */
1062 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1066 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1068 trace("test icon spacing\n");
1070 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(20, 30));
1071 ok(r
== MAKELONG(w
, h
) ||
1072 broken(r
== MAKELONG(w
, w
)), /* win98 */
1073 "Expected %d, got %d\n", MAKELONG(w
, h
), r
);
1075 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(25, 35));
1076 expect(MAKELONG(20,30), r
);
1078 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1,-1));
1079 expect(MAKELONG(25,35), r
);
1081 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_icon_spacing_seq
, "test icon spacing seq", FALSE
);
1083 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1084 DestroyWindow(hwnd
);
1087 static void test_color(void)
1089 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1096 COLORREF colors
[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE
, RGB(255,255,255)};
1098 hwnd
= create_listview_control(0);
1099 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1101 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1103 trace("test color seq\n");
1104 for (i
= 0; i
< 4; i
++)
1108 r
= SendMessage(hwnd
, LVM_SETBKCOLOR
, 0, color
);
1110 r
= SendMessage(hwnd
, LVM_GETBKCOLOR
, 0, color
);
1113 r
= SendMessage(hwnd
, LVM_SETTEXTCOLOR
, 0, color
);
1115 r
= SendMessage(hwnd
, LVM_GETTEXTCOLOR
, 0, color
);
1118 r
= SendMessage(hwnd
, LVM_SETTEXTBKCOLOR
, 0, color
);
1120 r
= SendMessage(hwnd
, LVM_GETTEXTBKCOLOR
, 0, color
);
1124 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_color_seq
, "test color seq", FALSE
);
1126 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1127 DestroyWindow(hwnd
);
1130 static void test_item_count(void)
1132 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1140 static CHAR item0text
[] = "item0";
1141 static CHAR item1text
[] = "item1";
1142 static CHAR item2text
[] = "item2";
1144 hwnd
= create_listview_control(0);
1145 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1147 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1149 trace("test item count\n");
1151 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1155 item0
.mask
= LVIF_TEXT
;
1158 item0
.pszText
= item0text
;
1159 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1162 /* [item0, item1] */
1163 item1
.mask
= LVIF_TEXT
;
1166 item1
.pszText
= item1text
;
1167 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1170 /* [item0, item1, item2] */
1171 item2
.mask
= LVIF_TEXT
;
1174 item2
.pszText
= item2text
;
1175 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1178 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1181 /* [item0, item1] */
1182 r
= SendMessage(hwnd
, LVM_DELETEITEM
, 2, 0);
1185 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1189 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
1192 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1196 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1199 /* [item0, item1] */
1200 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1203 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1206 /* [item0, item1, item2] */
1207 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1210 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1213 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_item_count_seq
, "test item count seq", FALSE
);
1215 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1216 DestroyWindow(hwnd
);
1219 static void test_item_position(void)
1221 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1230 static CHAR item0text
[] = "item0";
1231 static CHAR item1text
[] = "item1";
1232 static CHAR item2text
[] = "item2";
1234 hwnd
= create_custom_listview_control(LVS_ICON
);
1235 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1237 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1239 trace("test item position\n");
1242 item0
.mask
= LVIF_TEXT
;
1245 item0
.pszText
= item0text
;
1246 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1249 /* [item0, item1] */
1250 item1
.mask
= LVIF_TEXT
;
1253 item1
.pszText
= item1text
;
1254 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1257 /* [item0, item1, item2] */
1258 item2
.mask
= LVIF_TEXT
;
1261 item2
.pszText
= item2text
;
1262 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1265 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 1, MAKELPARAM(10,5));
1267 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 1, (LPARAM
) &position
);
1269 expect2(10, 5, position
.x
, position
.y
);
1271 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 2, MAKELPARAM(0,0));
1273 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 2, (LPARAM
) &position
);
1275 expect2(0, 0, position
.x
, position
.y
);
1277 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 0, MAKELPARAM(20,20));
1279 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
) &position
);
1281 expect2(20, 20, position
.x
, position
.y
);
1283 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_itempos_seq
, "test item position seq", TRUE
);
1285 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1286 DestroyWindow(hwnd
);
1289 static void test_getorigin(void)
1297 position
.x
= position
.y
= 0;
1299 hwnd
= create_custom_listview_control(LVS_ICON
);
1300 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1301 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1302 trace("test get origin results\n");
1303 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1305 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1306 DestroyWindow(hwnd
);
1308 hwnd
= create_custom_listview_control(LVS_SMALLICON
);
1309 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1310 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1311 trace("test get origin results\n");
1312 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1314 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1315 DestroyWindow(hwnd
);
1317 hwnd
= create_custom_listview_control(LVS_LIST
);
1318 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1319 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1320 trace("test get origin results\n");
1321 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1323 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1324 DestroyWindow(hwnd
);
1326 hwnd
= create_custom_listview_control(LVS_REPORT
);
1327 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1328 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1329 trace("test get origin results\n");
1330 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1332 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1333 DestroyWindow(hwnd
);
1337 static void test_multiselect(void)
1339 typedef struct t_select_task
1350 int i
,j
,item_count
,selected_count
;
1351 static const int items
=5;
1356 static struct t_select_task task_list
[] = {
1357 { "using VK_DOWN", 0, VK_DOWN
, -1, -1 },
1358 { "using VK_UP", -1, VK_UP
, -1, -1 },
1359 { "using VK_END", 0, VK_END
, 1, -1 },
1360 { "using VK_HOME", -1, VK_HOME
, 1, -1 }
1364 hwnd
= create_listview_control(0);
1366 for (i
=0;i
<items
;i
++) {
1367 insert_item(hwnd
, 0);
1370 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1372 expect(items
,item_count
);
1375 task
= task_list
[i
];
1377 /* deselect all items */
1378 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1379 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1381 /* set initial position */
1382 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, (task
.initPos
== -1 ? item_count
-1 : task
.initPos
));
1383 ListView_SetItemState(hwnd
,(task
.initPos
== -1 ? item_count
-1 : task
.initPos
),LVIS_SELECTED
,LVIS_SELECTED
);
1385 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1387 ok(selected_count
== 1, "There should be only one selected item at the beginning (is %d)\n",selected_count
);
1389 /* Set SHIFT key pressed */
1390 GetKeyboardState(kstate
);
1391 kstate
[VK_SHIFT
]=0x80;
1392 SetKeyboardState(kstate
);
1394 for (j
=1;j
<=(task
.count
== -1 ? item_count
: task
.count
);j
++) {
1395 r
= SendMessage(hwnd
, WM_KEYDOWN
, task
.loopVK
, 0);
1397 r
= SendMessage(hwnd
, WM_KEYUP
, task
.loopVK
, 0);
1401 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1403 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
);
1405 /* Set SHIFT key released */
1406 GetKeyboardState(kstate
);
1407 kstate
[VK_SHIFT
]=0x00;
1408 SetKeyboardState(kstate
);
1410 DestroyWindow(hwnd
);
1412 /* make multiple selection, then switch to LVS_SINGLESEL */
1413 hwnd
= create_listview_control(0);
1414 for (i
=0;i
<items
;i
++) {
1415 insert_item(hwnd
, 0);
1417 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1418 expect(items
,item_count
);
1419 /* deselect all items */
1420 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1421 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1423 ListView_SetItemState(hwnd
, i
, LVIS_SELECTED
, LVIS_SELECTED
);
1426 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1428 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1432 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1433 ok(!(style
& LVS_SINGLESEL
), "LVS_SINGLESEL isn't expected\n");
1434 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SINGLESEL
);
1435 /* check that style is accepted */
1436 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1437 ok(style
& LVS_SINGLESEL
, "LVS_SINGLESEL expected\n");
1440 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1441 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1443 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1445 SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1448 /* select one more */
1449 ListView_SetItemState(hwnd
, 3, LVIS_SELECTED
, LVIS_SELECTED
);
1452 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1453 ok(!(r
& LVIS_SELECTED
), "Expected item %d to be unselected\n", i
);
1455 r
= ListView_GetItemState(hwnd
, 3, LVIS_SELECTED
);
1456 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1458 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1460 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1464 DestroyWindow(hwnd
);
1467 static void test_subitem_rect(void)
1474 /* test LVM_GETSUBITEMRECT for header */
1475 hwnd
= create_listview_control(0);
1476 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1477 /* add some columns */
1478 memset(&col
, 0, sizeof(LVCOLUMN
));
1479 col
.mask
= LVCF_WIDTH
;
1482 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1486 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 1, (LPARAM
)&col
);
1490 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 2, (LPARAM
)&col
);
1492 /* item = -1 means header, subitem index is 1 based */
1493 rect
.left
= LVIR_BOUNDS
;
1495 rect
.right
= rect
.bottom
= 0;
1496 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1499 rect
.left
= LVIR_BOUNDS
;
1501 rect
.right
= rect
.bottom
= 0;
1502 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1504 ok(r
!= 0, "Expected not-null LRESULT\n");
1505 expect(100, rect
.left
);
1506 expect(250, rect
.right
);
1507 expect(3, rect
.top
);
1509 rect
.left
= LVIR_BOUNDS
;
1511 rect
.right
= rect
.bottom
= 0;
1512 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1514 ok(r
!= 0, "Expected not-null LRESULT\n");
1515 expect(250, rect
.left
);
1516 expect(450, rect
.right
);
1517 expect(3, rect
.top
);
1520 DestroyWindow(hwnd
);
1523 /* comparison callback for test_sorting */
1524 static INT WINAPI
test_CallBackCompare(LPARAM first
, LPARAM second
, LPARAM lParam
)
1526 if (first
== second
) return 0;
1527 return (first
> second
? 1 : -1);
1530 static void test_sorting(void)
1536 hwnd
= create_listview_control(0);
1537 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1539 /* insert some items */
1540 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
1541 item
.state
= LVIS_SELECTED
;
1545 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1548 item
.mask
= LVIF_PARAM
;
1552 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1555 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
1556 item
.state
= LVIS_SELECTED
;
1560 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1563 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1566 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1569 r
= SendMessage(hwnd
, LVM_SORTITEMS
, 0, (LPARAM
)test_CallBackCompare
);
1572 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1574 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1576 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 0, LVIS_SELECTED
);
1578 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 1, LVIS_SELECTED
);
1579 expect(LVIS_SELECTED
, r
);
1580 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 2, LVIS_SELECTED
);
1581 expect(LVIS_SELECTED
, r
);
1583 DestroyWindow(hwnd
);
1586 static void test_ownerdata(void)
1589 LONG_PTR style
, ret
;
1593 /* it isn't possible to set LVS_OWNERDATA after creation */
1594 hwnd
= create_listview_control(0);
1595 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1596 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1597 ok(!(style
& LVS_OWNERDATA
) && style
, "LVS_OWNERDATA isn't expected\n");
1599 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1601 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1602 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1603 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1604 "try to switch to LVS_OWNERDATA seq", FALSE
);
1606 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1607 ok(!(style
& LVS_OWNERDATA
), "LVS_OWNERDATA isn't expected\n");
1608 DestroyWindow(hwnd
);
1610 /* try to set LVS_OWNERDATA after creation just having it */
1611 hwnd
= create_listview_control(LVS_OWNERDATA
);
1612 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1613 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1614 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1616 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1618 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1619 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1620 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1621 "try to switch to LVS_OWNERDATA seq", FALSE
);
1622 DestroyWindow(hwnd
);
1624 /* try to remove LVS_OWNERDATA after creation just having it */
1625 hwnd
= create_listview_control(LVS_OWNERDATA
);
1626 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1627 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1628 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1630 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1632 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
& ~LVS_OWNERDATA
);
1633 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1634 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1635 "try to switch to LVS_OWNERDATA seq", FALSE
);
1636 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1637 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1638 DestroyWindow(hwnd
);
1640 /* try select an item */
1641 hwnd
= create_listview_control(LVS_OWNERDATA
);
1642 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1643 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1644 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1645 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1647 memset(&item
, 0, sizeof(item
));
1648 item
.stateMask
= LVIS_SELECTED
;
1649 item
.state
= LVIS_SELECTED
;
1650 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
1652 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1654 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1656 DestroyWindow(hwnd
);
1658 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
1659 hwnd
= create_listview_control(LVS_OWNERDATA
);
1660 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1661 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1662 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1663 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1665 memset(&item
, 0, sizeof(item
));
1666 item
.mask
= LVIF_STATE
;
1668 item
.stateMask
= LVIS_SELECTED
;
1669 item
.state
= LVIS_SELECTED
;
1670 res
= SendMessageA(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
1672 DestroyWindow(hwnd
);
1675 START_TEST(listview
)
1678 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
1680 hComctl32
= GetModuleHandleA("comctl32.dll");
1681 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
1682 if (pInitCommonControlsEx
)
1684 INITCOMMONCONTROLSEX iccex
;
1685 iccex
.dwSize
= sizeof(iccex
);
1686 iccex
.dwICC
= ICC_LISTVIEW_CLASSES
;
1687 pInitCommonControlsEx(&iccex
);
1690 InitCommonControls();
1692 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1694 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1695 hwndparent
= create_parent_window();
1696 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent window", TRUE
);
1697 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1705 test_icon_spacing();
1708 test_item_position();
1712 test_subitem_rect();