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 PARENT_FULL_SEQ_INDEX 1
31 #define LISTVIEW_SEQ_INDEX 2
32 #define NUM_MSG_SEQUENCES 3
37 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
38 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
39 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
43 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
45 static const struct message create_parent_wnd_seq
[] = {
46 { WM_GETMINMAXINFO
, sent
},
47 { WM_NCCREATE
, sent
},
48 { WM_NCCALCSIZE
, sent
|wparam
, 0 },
50 { WM_SHOWWINDOW
, sent
|wparam
, 1 },
51 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
52 { WM_QUERYNEWPALETTE
, sent
|optional
},
53 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
54 { WM_WINDOWPOSCHANGED
, sent
|optional
},
55 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
56 { WM_ACTIVATEAPP
, sent
|wparam
, 1 },
57 { WM_NCACTIVATE
, sent
|wparam
, 1 },
58 { WM_ACTIVATE
, sent
|wparam
, 1 },
59 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
60 { WM_IME_NOTIFY
, sent
|defwinproc
|optional
},
61 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
62 /* Win9x adds SWP_NOZORDER below */
63 { WM_WINDOWPOSCHANGED
, sent
, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
64 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
70 static const struct message redraw_listview_seq
[] = {
71 { WM_PAINT
, sent
|id
, 0, 0, LISTVIEW_ID
},
72 { WM_PAINT
, sent
|id
, 0, 0, HEADER_ID
},
73 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
74 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
75 { WM_NOTIFY
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
76 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
77 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
81 static const struct message listview_icon_spacing_seq
[] = {
82 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(20, 30) },
83 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(25, 35) },
84 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(-1, -1) },
88 static const struct message listview_color_seq
[] = {
89 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
90 { LVM_GETBKCOLOR
, sent
},
91 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
92 { LVM_GETTEXTCOLOR
, sent
},
93 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
94 { LVM_GETTEXTBKCOLOR
, sent
},
96 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
97 { LVM_GETBKCOLOR
, sent
},
98 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
99 { LVM_GETTEXTCOLOR
, sent
},
100 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
101 { LVM_GETTEXTBKCOLOR
, sent
},
103 { LVM_SETBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
104 { LVM_GETBKCOLOR
, sent
},
105 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, CLR_NONE
},
106 { LVM_GETTEXTCOLOR
, sent
},
107 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
108 { LVM_GETTEXTBKCOLOR
, sent
},
110 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
111 { LVM_GETBKCOLOR
, sent
},
112 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
113 { LVM_GETTEXTCOLOR
, sent
},
114 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
115 { LVM_GETTEXTBKCOLOR
, sent
},
119 static const struct message listview_item_count_seq
[] = {
120 { LVM_GETITEMCOUNT
, sent
},
121 { LVM_INSERTITEM
, sent
},
122 { LVM_INSERTITEM
, sent
},
123 { LVM_INSERTITEM
, sent
},
124 { LVM_GETITEMCOUNT
, sent
},
125 { LVM_DELETEITEM
, sent
|wparam
, 2 },
126 { LVM_GETITEMCOUNT
, sent
},
127 { LVM_DELETEALLITEMS
, sent
},
128 { LVM_GETITEMCOUNT
, sent
},
129 { LVM_INSERTITEM
, sent
},
130 { LVM_INSERTITEM
, sent
},
131 { LVM_GETITEMCOUNT
, sent
},
132 { LVM_INSERTITEM
, sent
},
133 { LVM_GETITEMCOUNT
, sent
},
137 static const struct message listview_itempos_seq
[] = {
138 { LVM_INSERTITEM
, sent
},
139 { LVM_INSERTITEM
, sent
},
140 { LVM_INSERTITEM
, sent
},
141 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 1, MAKELPARAM(10,5) },
142 { LVM_GETITEMPOSITION
, sent
|wparam
, 1 },
143 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 2, MAKELPARAM(0,0) },
144 { LVM_GETITEMPOSITION
, sent
|wparam
, 2 },
145 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 0, MAKELPARAM(20,20) },
146 { LVM_GETITEMPOSITION
, sent
|wparam
, 0 },
150 static const struct message listview_ownerdata_switchto_seq
[] = {
151 { WM_STYLECHANGING
, sent
},
152 { WM_STYLECHANGED
, sent
},
156 static const struct message listview_getorderarray_seq
[] = {
157 { LVM_GETCOLUMNORDERARRAY
, sent
|id
|wparam
, 2, 0, LISTVIEW_ID
},
158 { HDM_GETORDERARRAY
, sent
|id
|wparam
, 2, 0, HEADER_ID
},
162 static const struct message empty_seq
[] = {
166 static const struct message forward_erasebkgnd_parent_seq
[] = {
167 { WM_ERASEBKGND
, sent
},
176 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
178 static LONG defwndproc_counter
= 0;
182 msg
.message
= message
;
183 msg
.flags
= sent
|wparam
|lparam
;
184 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
188 /* log system messages, except for painting */
189 if (message
< WM_USER
&&
190 message
!= WM_PAINT
&&
191 message
!= WM_ERASEBKGND
&&
192 message
!= WM_NCPAINT
&&
193 message
!= WM_NCHITTEST
&&
194 message
!= WM_GETTEXT
&&
195 message
!= WM_GETICON
&&
196 message
!= WM_DEVICECHANGE
)
198 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
200 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
202 add_message(sequences
, PARENT_FULL_SEQ_INDEX
, &msg
);
204 defwndproc_counter
++;
205 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
206 defwndproc_counter
--;
211 static BOOL
register_parent_wnd_class(void)
216 cls
.lpfnWndProc
= parent_wnd_proc
;
219 cls
.hInstance
= GetModuleHandleA(NULL
);
221 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
222 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
223 cls
.lpszMenuName
= NULL
;
224 cls
.lpszClassName
= "Listview test parent class";
225 return RegisterClassA(&cls
);
228 static HWND
create_parent_window(void)
230 if (!register_parent_wnd_class())
233 return CreateWindowEx(0, "Listview test parent class",
234 "Listview test parent window",
235 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
236 WS_MAXIMIZEBOX
| WS_VISIBLE
,
238 GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
241 static LRESULT WINAPI
listview_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
243 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
244 static LONG defwndproc_counter
= 0;
248 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
250 /* some debug output for style changing */
251 if ((message
== WM_STYLECHANGING
||
252 message
== WM_STYLECHANGED
) && lParam
)
254 STYLESTRUCT
*style
= (STYLESTRUCT
*)lParam
;
255 trace("\told style: 0x%08x, new style: 0x%08x\n", style
->styleOld
, style
->styleNew
);
258 msg
.message
= message
;
259 msg
.flags
= sent
|wparam
|lparam
;
260 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
263 msg
.id
= LISTVIEW_ID
;
264 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
266 defwndproc_counter
++;
267 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
268 defwndproc_counter
--;
272 static HWND
create_listview_control(DWORD style
)
274 struct subclass_info
*info
;
278 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
282 GetClientRect(hwndparent
, &rect
);
283 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
284 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| LVS_REPORT
| style
,
285 0, 0, rect
.right
, rect
.bottom
,
286 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
287 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
291 HeapFree(GetProcessHeap(), 0, info
);
295 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
296 (LONG_PTR
)listview_subclass_proc
);
297 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
302 static HWND
create_custom_listview_control(DWORD style
)
304 struct subclass_info
*info
;
308 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
312 GetClientRect(hwndparent
, &rect
);
313 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
314 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
315 0, 0, rect
.right
, rect
.bottom
,
316 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
317 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
321 HeapFree(GetProcessHeap(), 0, info
);
325 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
326 (LONG_PTR
)listview_subclass_proc
);
327 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
332 static LRESULT WINAPI
header_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
334 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
335 static LONG defwndproc_counter
= 0;
339 trace("header: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
341 msg
.message
= message
;
342 msg
.flags
= sent
|wparam
|lparam
;
343 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
347 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
349 defwndproc_counter
++;
350 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
351 defwndproc_counter
--;
355 static HWND
subclass_header(HWND hwndListview
)
357 struct subclass_info
*info
;
360 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
364 hwnd
= ListView_GetHeader(hwndListview
);
365 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
366 (LONG_PTR
)header_subclass_proc
);
367 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
372 static void test_images(void)
380 static CHAR hello
[] = "hello";
382 himl
= ImageList_Create(40, 40, 0, 4, 4);
383 ok(himl
!= NULL
, "failed to create imagelist\n");
385 hbmp
= CreateBitmap(40, 40, 1, 1, NULL
);
386 ok(hbmp
!= NULL
, "failed to create bitmap\n");
388 r
= ImageList_Add(himl
, hbmp
, 0);
389 ok(r
== 0, "should be zero\n");
391 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED
,
392 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
393 ok(hwnd
!= NULL
, "failed to create listview window\n");
395 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, 0x940);
396 ok(r
== 0, "should return zero\n");
398 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)himl
);
399 ok(r
== 0, "should return zero\n");
401 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELONG(100,50));
402 /* returns dimensions */
404 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
405 ok(r
== 0, "should be zero items\n");
407 item
.mask
= LVIF_IMAGE
| LVIF_TEXT
;
412 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
413 ok(r
== -1, "should fail\n");
416 item
.pszText
= hello
;
417 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
418 ok(r
== 0, "should not fail\n");
420 memset(&r1
, 0, sizeof r1
);
422 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r1
);
424 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
425 ok(r
== TRUE
, "should not fail\n");
428 item
.pszText
= hello
;
429 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
430 ok(r
== 0, "should not fail\n");
432 memset(&r2
, 0, sizeof r2
);
434 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r2
);
436 ok(!memcmp(&r1
, &r2
, sizeof r1
), "rectangle should be the same\n");
441 static void test_checkboxes(void)
446 static CHAR text
[] = "Text",
450 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
451 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
452 ok(hwnd
!= NULL
, "failed to create listview window\n");
454 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
455 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
456 item
.stateMask
= 0xffff;
461 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
462 ok(r
== 0, "ret %d\n", r
);
465 item
.mask
= LVIF_STATE
;
466 item
.stateMask
= 0xffff;
467 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
468 ok(item
.state
== 0xfccc, "state %x\n", item
.state
);
470 /* Don't set LVIF_STATE */
471 item
.mask
= LVIF_TEXT
;
472 item
.stateMask
= 0xffff;
477 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
478 ok(r
== 1, "ret %d\n", r
);
481 item
.mask
= LVIF_STATE
;
482 item
.stateMask
= 0xffff;
483 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
484 ok(item
.state
== 0, "state %x\n", item
.state
);
486 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
487 ok(r
== 0, "should return zero\n");
489 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
491 item
.mask
= LVIF_STATE
;
492 item
.stateMask
= 0xffff;
493 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
494 ok(item
.state
== 0x1ccc, "state %x\n", item
.state
);
496 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
498 item
.mask
= LVIF_TEXT
;
500 item
.pszText
= text2
;
501 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
502 ok(r
== 2, "ret %d\n", r
);
505 item
.mask
= LVIF_STATE
;
506 item
.stateMask
= 0xffff;
507 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
508 ok(item
.state
== 0x1000, "state %x\n", item
.state
);
510 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
512 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
513 item
.stateMask
= 0xffff;
515 item
.pszText
= text3
;
516 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
517 ok(r
== 3, "ret %d\n", r
);
520 item
.mask
= LVIF_STATE
;
521 item
.stateMask
= 0xffff;
522 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
523 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
525 /* Set an item's state to checked */
527 item
.mask
= LVIF_STATE
;
528 item
.stateMask
= 0xf000;
530 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
533 item
.mask
= LVIF_STATE
;
534 item
.stateMask
= 0xffff;
535 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
536 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
538 /* Check that only the bits we asked for are returned,
539 * and that all the others are set to zero
542 item
.mask
= LVIF_STATE
;
543 item
.stateMask
= 0xf000;
545 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
546 ok(item
.state
== 0x2000, "state %x\n", item
.state
);
548 /* Set the style again and check that doesn't change an item's state */
549 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
550 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
553 item
.mask
= LVIF_STATE
;
554 item
.stateMask
= 0xffff;
555 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
556 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
558 /* Unsetting the checkbox extended style doesn't change an item's state */
559 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, 0);
560 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
563 item
.mask
= LVIF_STATE
;
564 item
.stateMask
= 0xffff;
565 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
566 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
568 /* Now setting the style again will change an item's state */
569 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
570 ok(r
== 0, "ret %x\n", r
);
573 item
.mask
= LVIF_STATE
;
574 item
.stateMask
= 0xffff;
575 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
576 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
578 /* Toggle checkbox tests (bug 9934) */
579 memset (&item
, 0xcc, sizeof(item
));
580 item
.mask
= LVIF_STATE
;
583 item
.state
= LVIS_FOCUSED
;
584 item
.stateMask
= LVIS_FOCUSED
;
585 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
589 item
.mask
= LVIF_STATE
;
590 item
.stateMask
= 0xffff;
591 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
592 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
594 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
596 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
600 item
.mask
= LVIF_STATE
;
601 item
.stateMask
= 0xffff;
602 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
603 ok(item
.state
== 0x2aab, "state %x\n", item
.state
);
605 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
607 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
611 item
.mask
= LVIF_STATE
;
612 item
.stateMask
= 0xffff;
613 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
614 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
619 static void insert_column(HWND hwnd
, int idx
)
624 memset(&column
, 0xcc, sizeof(column
));
625 column
.mask
= LVCF_SUBITEM
;
626 column
.iSubItem
= idx
;
628 rc
= ListView_InsertColumn(hwnd
, idx
, &column
);
632 static void insert_item(HWND hwnd
, int idx
)
634 static CHAR text
[] = "foo";
639 memset(&item
, 0xcc, sizeof (item
));
640 item
.mask
= LVIF_TEXT
;
645 rc
= ListView_InsertItem(hwnd
, &item
);
649 static void test_items(void)
651 const LPARAM lparamTest
= 0x42;
655 static CHAR text
[] = "Text";
657 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
658 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
659 ok(hwnd
!= NULL
, "failed to create listview window\n");
662 * Test setting/getting item params
665 /* Set up two columns */
666 insert_column(hwnd
, 0);
667 insert_column(hwnd
, 1);
669 /* LVIS_SELECTED with zero stateMask */
671 memset (&item
, 0, sizeof (item
));
672 item
.mask
= LVIF_STATE
;
673 item
.state
= LVIS_SELECTED
;
677 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
678 ok(r
== 0, "ret %d\n", r
);
680 memset (&item
, 0xcc, sizeof (item
));
681 item
.mask
= LVIF_STATE
;
682 item
.stateMask
= LVIS_SELECTED
;
686 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
687 ok(r
!= 0, "ret %d\n", r
);
688 ok(item
.state
& LVIS_SELECTED
, "Expected LVIS_SELECTED\n");
689 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
691 /* LVIS_SELECTED with zero stateMask */
693 memset (&item
, 0, sizeof (item
));
694 item
.mask
= LVIF_STATE
;
695 item
.state
= LVIS_FOCUSED
;
699 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
700 ok(r
== 0, "ret %d\n", r
);
702 memset (&item
, 0xcc, sizeof (item
));
703 item
.mask
= LVIF_STATE
;
704 item
.stateMask
= LVIS_FOCUSED
;
708 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
709 ok(r
!= 0, "ret %d\n", r
);
710 ok(item
.state
& LVIS_FOCUSED
, "Expected LVIS_FOCUSED\n");
711 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
713 /* LVIS_CUT with LVIS_FOCUSED stateMask */
715 memset (&item
, 0, sizeof (item
));
716 item
.mask
= LVIF_STATE
;
717 item
.state
= LVIS_CUT
;
718 item
.stateMask
= LVIS_FOCUSED
;
721 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
722 ok(r
== 0, "ret %d\n", r
);
724 memset (&item
, 0xcc, sizeof (item
));
725 item
.mask
= LVIF_STATE
;
726 item
.stateMask
= LVIS_CUT
;
730 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
731 ok(r
!= 0, "ret %d\n", r
);
732 ok(item
.state
& LVIS_CUT
, "Expected LVIS_CUT\n");
733 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
735 /* Insert an item with just a param */
736 memset (&item
, 0xcc, sizeof (item
));
737 item
.mask
= LVIF_PARAM
;
740 item
.lParam
= lparamTest
;
741 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
742 ok(r
== 0, "ret %d\n", r
);
744 /* Test getting of the 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 a subitem */
754 memset (&item
, 0xcc, sizeof (item
));
755 item
.mask
= LVIF_TEXT
;
759 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
760 ok(r
!= 0, "ret %d\n", r
);
762 /* Query param from subitem: returns 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 /* Set up param on first subitem: no effect */
772 memset (&item
, 0xcc, sizeof (item
));
773 item
.mask
= LVIF_PARAM
;
776 item
.lParam
= lparamTest
+1;
777 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
778 ok(r
== 0, "ret %d\n", r
);
780 /* Query param from subitem again: should still return main item param */
781 memset (&item
, 0xcc, sizeof (item
));
782 item
.mask
= LVIF_PARAM
;
785 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
786 ok(r
!= 0, "ret %d\n", r
);
787 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
789 /**** Some tests of state highlighting ****/
790 memset (&item
, 0xcc, sizeof (item
));
791 item
.mask
= LVIF_STATE
;
794 item
.state
= LVIS_SELECTED
;
795 item
.stateMask
= LVIS_SELECTED
| LVIS_DROPHILITED
;
796 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
797 ok(r
!= 0, "ret %d\n", r
);
799 item
.state
= LVIS_DROPHILITED
;
800 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
801 ok(r
!= 0, "ret %d\n", r
);
803 memset (&item
, 0xcc, sizeof (item
));
804 item
.mask
= LVIF_STATE
;
808 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
809 ok(r
!= 0, "ret %d\n", r
);
810 ok(item
.state
== LVIS_SELECTED
, "got state %x, expected %x\n", item
.state
, LVIS_SELECTED
);
812 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
813 ok(r
!= 0, "ret %d\n", r
);
814 todo_wine
ok(item
.state
== LVIS_DROPHILITED
, "got state %x, expected %x\n", item
.state
, LVIS_DROPHILITED
);
816 /* some notnull but meaningless masks */
817 memset (&item
, 0, sizeof(item
));
818 item
.mask
= LVIF_NORECOMPUTE
;
821 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
822 ok(r
!= 0, "ret %d\n", r
);
823 memset (&item
, 0, sizeof(item
));
824 item
.mask
= LVIF_DI_SETITEM
;
827 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
828 ok(r
!= 0, "ret %d\n", r
);
833 static void test_columns(void)
835 HWND hwnd
, hwndheader
;
840 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
841 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
842 ok(hwnd
!= NULL
, "failed to create listview window\n");
844 /* Add a column with no mask */
845 memset(&column
, 0xcc, sizeof(column
));
847 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
848 ok(rc
==0, "Inserting column with no mask failed with %d\n", rc
);
850 /* Check its width */
851 rc
= ListView_GetColumnWidth(hwnd
, 0);
853 broken(rc
==0), /* win9x */
854 "Inserting column with no mask failed to set width to 10 with %d\n", rc
);
858 /* LVM_GETCOLUMNORDERARRAY */
859 hwnd
= create_listview_control(0);
860 hwndheader
= subclass_header(hwnd
);
862 memset(&column
, 0, sizeof(column
));
863 column
.mask
= LVCF_WIDTH
;
865 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
866 ok(rc
== 0, "Inserting column failed with %d\n", rc
);
869 rc
= ListView_InsertColumn(hwnd
, 1, &column
);
870 ok(rc
== 1, "Inserting column failed with %d\n", rc
);
872 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
874 rc
= SendMessage(hwnd
, LVM_GETCOLUMNORDERARRAY
, 2, (LPARAM
)&order
);
875 ok(rc
!= 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
876 ok(order
[0] == 0, "Expected order 0, got %d\n", order
[0]);
877 ok(order
[1] == 1, "Expected order 1, got %d\n", order
[1]);
879 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_getorderarray_seq
, "get order array", FALSE
);
883 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
884 static WNDPROC listviewWndProc
;
885 static HIMAGELIST test_create_imagelist
;
887 static LRESULT CALLBACK
create_test_wndproc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
891 if (uMsg
== WM_CREATE
)
893 LPCREATESTRUCT lpcs
= (LPCREATESTRUCT
)lParam
;
894 lpcs
->style
|= LVS_REPORT
;
896 ret
= CallWindowProc(listviewWndProc
, hwnd
, uMsg
, wParam
, lParam
);
897 if (uMsg
== WM_CREATE
) SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)test_create_imagelist
);
901 static void test_create(void)
910 cls
.cbSize
= sizeof(WNDCLASSEX
);
911 ok(GetClassInfoEx(GetModuleHandle(NULL
), "SysListView32", &cls
), "GetClassInfoEx failed\n");
912 listviewWndProc
= cls
.lpfnWndProc
;
913 cls
.lpfnWndProc
= create_test_wndproc
;
914 cls
.lpszClassName
= "MyListView32";
915 ok(RegisterClassEx(&cls
), "RegisterClassEx failed\n");
917 test_create_imagelist
= ImageList_Create(16, 16, 0, 5, 10);
918 hList
= CreateWindow("MyListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
919 ok((HIMAGELIST
)SendMessage(hList
, LVM_GETIMAGELIST
, 0, 0) == test_create_imagelist
, "Image list not obtained\n");
920 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
921 ok(IsWindow(hHeader
) && IsWindowVisible(hHeader
), "Listview not in report mode\n");
922 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
923 DestroyWindow(hList
);
925 /* header isn't created on LVS_ICON and LVS_LIST styles */
926 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
927 GetModuleHandle(NULL
), 0);
928 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
929 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
930 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
932 memset(&col
, 0, sizeof(LVCOLUMNA
));
933 col
.mask
= LVCF_WIDTH
;
935 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
936 ok(r
== 0, "Expected 0 column's inserted\n");
937 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
938 ok(IsWindow(hHeader
), "Header should be created\n");
939 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
940 DestroyWindow(hList
);
942 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
943 GetModuleHandle(NULL
), 0);
944 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
945 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
946 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
948 memset(&col
, 0, sizeof(LVCOLUMNA
));
949 col
.mask
= LVCF_WIDTH
;
951 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
952 ok(r
== 0, "Expected 0 column's inserted\n");
953 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
954 ok(IsWindow(hHeader
), "Header should be created\n");
955 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
956 DestroyWindow(hList
);
958 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
959 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
960 GetModuleHandle(NULL
), 0);
961 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLongPtr(hList
, GWL_STYLE
) | LVS_REPORT
);
962 ok(ret
& WS_VISIBLE
, "Style wrong, should have WS_VISIBLE\n");
963 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
964 ok(IsWindow(hHeader
), "Header should be created\n");
965 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLong(hList
, GWL_STYLE
) & ~LVS_REPORT
);
966 ok((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
967 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
968 ok(IsWindow(hHeader
), "Header should be created\n");
969 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
970 DestroyWindow(hList
);
972 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
973 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
974 GetModuleHandle(NULL
), 0);
975 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
976 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_LIST
) | LVS_REPORT
);
977 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_LIST
)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
978 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
979 ok(IsWindow(hHeader
), "Header should be created\n");
980 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
981 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
982 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_REPORT
) | LVS_LIST
);
983 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
984 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
985 ok(IsWindow(hHeader
), "Header should be created\n");
986 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
987 DestroyWindow(hList
);
989 /* LVS_REPORT without WS_VISIBLE */
990 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
991 GetModuleHandle(NULL
), 0);
992 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
993 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
994 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
996 memset(&col
, 0, sizeof(LVCOLUMNA
));
997 col
.mask
= LVCF_WIDTH
;
999 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1000 ok(r
== 0, "Expected 0 column's inserted\n");
1001 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1002 ok(IsWindow(hHeader
), "Header should be created\n");
1003 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1004 DestroyWindow(hList
);
1006 /* LVS_REPORT without WS_VISIBLE, try to show it */
1007 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1008 GetModuleHandle(NULL
), 0);
1009 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1010 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1011 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1012 ShowWindow(hList
, SW_SHOW
);
1013 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1014 ok(IsWindow(hHeader
), "Header should be created\n");
1015 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1016 DestroyWindow(hList
);
1018 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1019 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
|LVS_NOCOLUMNHEADER
|WS_VISIBLE
,
1020 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
1021 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1022 ok(IsWindow(hHeader
), "Header should be created\n");
1023 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1024 /* HDS_DRAGDROP set by default */
1025 ok(GetWindowLongPtr(hHeader
, GWL_STYLE
) & HDS_DRAGDROP
, "Expected header to have HDS_DRAGDROP\n");
1026 DestroyWindow(hList
);
1028 /* setting LVS_EX_HEADERDRAGDROP creates header */
1029 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1030 GetModuleHandle(NULL
), 0);
1031 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1032 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1033 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1034 SendMessage(hList
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_HEADERDRAGDROP
);
1035 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1036 ok(IsWindow(hHeader
), "Header should be created\n");
1037 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1038 DestroyWindow(hList
);
1040 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1041 hList
= create_custom_listview_control(0);
1042 SendMessage(hList
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_HEADERDRAGDROP
);
1043 r
= SendMessage(hList
, LVM_GETEXTENDEDLISTVIEWSTYLE
, 0, 0);
1044 ok(r
& LVS_EX_HEADERDRAGDROP
, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1045 DestroyWindow(hList
);
1047 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1048 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1049 GetModuleHandle(NULL
), 0);
1050 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1051 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1053 rect
.left
= LVIR_BOUNDS
;
1055 rect
.right
= rect
.bottom
= -10;
1056 r
= SendMessage(hList
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1057 ok(r
!= 0, "Expected not-null LRESULT\n");
1059 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1060 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1061 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1063 DestroyWindow(hList
);
1066 static void test_redraw(void)
1068 HWND hwnd
, hwndheader
;
1073 hwnd
= create_listview_control(0);
1074 hwndheader
= subclass_header(hwnd
);
1076 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1078 trace("invalidate & update\n");
1079 InvalidateRect(hwnd
, NULL
, TRUE
);
1081 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, redraw_listview_seq
, "redraw listview", FALSE
);
1083 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1085 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1086 /* 1. Without backbuffer */
1087 res
= ListView_SetBkColor(hwnd
, CLR_NONE
);
1090 hdc
= GetWindowDC(hwndparent
);
1092 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1093 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1094 ok(r
!= 0, "Expected not zero result\n");
1095 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, forward_erasebkgnd_parent_seq
,
1096 "forward WM_ERASEBKGND on CLR_NONE", FALSE
);
1098 res
= ListView_SetBkColor(hwnd
, CLR_DEFAULT
);
1101 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1102 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1103 ok(r
!= 0, "Expected not zero result\n");
1104 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, empty_seq
,
1105 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE
);
1107 /* 2. With backbuffer */
1108 SendMessageA(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_DOUBLEBUFFER
,
1109 LVS_EX_DOUBLEBUFFER
);
1110 res
= ListView_SetBkColor(hwnd
, CLR_NONE
);
1113 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1114 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1115 ok(r
!= 0, "Expected not zero result\n");
1116 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, forward_erasebkgnd_parent_seq
,
1117 "forward WM_ERASEBKGND on CLR_NONE", FALSE
);
1119 res
= ListView_SetBkColor(hwnd
, CLR_DEFAULT
);
1122 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1123 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1124 todo_wine
ok(r
!= 0, "Expected not zero result\n");
1125 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, empty_seq
,
1126 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE
);
1128 ReleaseDC(hwndparent
, hdc
);
1130 DestroyWindow(hwnd
);
1133 static LRESULT WINAPI
cd_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1135 COLORREF clr
, c0ffee
= RGB(0xc0, 0xff, 0xee);
1137 if(msg
== WM_NOTIFY
) {
1138 NMHDR
*nmhdr
= (PVOID
)lp
;
1139 if(nmhdr
->code
== NM_CUSTOMDRAW
) {
1140 NMLVCUSTOMDRAW
*nmlvcd
= (PVOID
)nmhdr
;
1141 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd
->nmcd
.dwDrawStage
);
1142 switch(nmlvcd
->nmcd
.dwDrawStage
) {
1144 SetBkColor(nmlvcd
->nmcd
.hdc
, c0ffee
);
1145 return CDRF_NOTIFYITEMDRAW
;
1146 case CDDS_ITEMPREPAINT
:
1147 nmlvcd
->clrTextBk
= CLR_DEFAULT
;
1148 return CDRF_NOTIFYSUBITEMDRAW
;
1149 case CDDS_ITEMPREPAINT
| CDDS_SUBITEM
:
1150 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1151 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1152 return CDRF_NOTIFYPOSTPAINT
;
1153 case CDDS_ITEMPOSTPAINT
| CDDS_SUBITEM
:
1154 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1155 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1156 return CDRF_DODEFAULT
;
1158 return CDRF_DODEFAULT
;
1162 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
1165 static void test_customdraw(void)
1170 hwnd
= create_listview_control(0);
1172 insert_column(hwnd
, 0);
1173 insert_column(hwnd
, 1);
1174 insert_item(hwnd
, 0);
1176 oldwndproc
= (WNDPROC
)SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
,
1177 (LONG_PTR
)cd_wndproc
);
1179 InvalidateRect(hwnd
, NULL
, TRUE
);
1182 SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
, (LONG_PTR
)oldwndproc
);
1184 DestroyWindow(hwnd
);
1187 static void test_icon_spacing(void)
1189 /* LVM_SETICONSPACING */
1190 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1196 hwnd
= create_custom_listview_control(LVS_ICON
);
1197 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1199 r
= SendMessage(hwnd
, WM_NOTIFYFORMAT
, (WPARAM
)hwndparent
, (LPARAM
)NF_REQUERY
);
1200 expect(NFR_ANSI
, r
);
1202 /* reset the icon spacing to defaults */
1203 SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1205 /* now we can request what the defaults are */
1206 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1210 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1212 trace("test icon spacing\n");
1214 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(20, 30));
1215 ok(r
== MAKELONG(w
, h
) ||
1216 broken(r
== MAKELONG(w
, w
)), /* win98 */
1217 "Expected %d, got %d\n", MAKELONG(w
, h
), r
);
1219 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(25, 35));
1220 expect(MAKELONG(20,30), r
);
1222 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1,-1));
1223 expect(MAKELONG(25,35), r
);
1225 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_icon_spacing_seq
, "test icon spacing seq", FALSE
);
1227 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1228 DestroyWindow(hwnd
);
1231 static void test_color(void)
1233 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1240 COLORREF colors
[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE
, RGB(255,255,255)};
1242 hwnd
= create_listview_control(0);
1243 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1245 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1247 trace("test color seq\n");
1248 for (i
= 0; i
< 4; i
++)
1252 r
= SendMessage(hwnd
, LVM_SETBKCOLOR
, 0, color
);
1254 r
= SendMessage(hwnd
, LVM_GETBKCOLOR
, 0, color
);
1257 r
= SendMessage(hwnd
, LVM_SETTEXTCOLOR
, 0, color
);
1259 r
= SendMessage(hwnd
, LVM_GETTEXTCOLOR
, 0, color
);
1262 r
= SendMessage(hwnd
, LVM_SETTEXTBKCOLOR
, 0, color
);
1264 r
= SendMessage(hwnd
, LVM_GETTEXTBKCOLOR
, 0, color
);
1268 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_color_seq
, "test color seq", FALSE
);
1270 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1271 DestroyWindow(hwnd
);
1274 static void test_item_count(void)
1276 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1284 static CHAR item0text
[] = "item0";
1285 static CHAR item1text
[] = "item1";
1286 static CHAR item2text
[] = "item2";
1288 hwnd
= create_listview_control(0);
1289 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1291 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1293 trace("test item count\n");
1295 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1299 item0
.mask
= LVIF_TEXT
;
1302 item0
.pszText
= item0text
;
1303 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1306 /* [item0, item1] */
1307 item1
.mask
= LVIF_TEXT
;
1310 item1
.pszText
= item1text
;
1311 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1314 /* [item0, item1, item2] */
1315 item2
.mask
= LVIF_TEXT
;
1318 item2
.pszText
= item2text
;
1319 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1322 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1325 /* [item0, item1] */
1326 r
= SendMessage(hwnd
, LVM_DELETEITEM
, 2, 0);
1329 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1333 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
1336 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1340 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1343 /* [item0, item1] */
1344 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1347 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1350 /* [item0, item1, item2] */
1351 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1354 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1357 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_item_count_seq
, "test item count seq", FALSE
);
1359 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1360 DestroyWindow(hwnd
);
1363 static void test_item_position(void)
1365 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1374 static CHAR item0text
[] = "item0";
1375 static CHAR item1text
[] = "item1";
1376 static CHAR item2text
[] = "item2";
1378 hwnd
= create_custom_listview_control(LVS_ICON
);
1379 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1381 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1383 trace("test item position\n");
1386 item0
.mask
= LVIF_TEXT
;
1389 item0
.pszText
= item0text
;
1390 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1393 /* [item0, item1] */
1394 item1
.mask
= LVIF_TEXT
;
1397 item1
.pszText
= item1text
;
1398 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1401 /* [item0, item1, item2] */
1402 item2
.mask
= LVIF_TEXT
;
1405 item2
.pszText
= item2text
;
1406 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1409 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 1, MAKELPARAM(10,5));
1411 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 1, (LPARAM
) &position
);
1413 expect2(10, 5, position
.x
, position
.y
);
1415 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 2, MAKELPARAM(0,0));
1417 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 2, (LPARAM
) &position
);
1419 expect2(0, 0, position
.x
, position
.y
);
1421 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 0, MAKELPARAM(20,20));
1423 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
) &position
);
1425 expect2(20, 20, position
.x
, position
.y
);
1427 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_itempos_seq
, "test item position seq", TRUE
);
1429 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1430 DestroyWindow(hwnd
);
1433 static void test_getorigin(void)
1441 position
.x
= position
.y
= 0;
1443 hwnd
= create_custom_listview_control(LVS_ICON
);
1444 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1445 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1446 trace("test get origin results\n");
1447 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1449 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1450 DestroyWindow(hwnd
);
1452 hwnd
= create_custom_listview_control(LVS_SMALLICON
);
1453 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1454 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1455 trace("test get origin results\n");
1456 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1458 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1459 DestroyWindow(hwnd
);
1461 hwnd
= create_custom_listview_control(LVS_LIST
);
1462 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1463 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1464 trace("test get origin results\n");
1465 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1467 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1468 DestroyWindow(hwnd
);
1470 hwnd
= create_custom_listview_control(LVS_REPORT
);
1471 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1472 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1473 trace("test get origin results\n");
1474 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1476 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1477 DestroyWindow(hwnd
);
1481 static void test_multiselect(void)
1483 typedef struct t_select_task
1494 int i
,j
,item_count
,selected_count
;
1495 static const int items
=5;
1500 static struct t_select_task task_list
[] = {
1501 { "using VK_DOWN", 0, VK_DOWN
, -1, -1 },
1502 { "using VK_UP", -1, VK_UP
, -1, -1 },
1503 { "using VK_END", 0, VK_END
, 1, -1 },
1504 { "using VK_HOME", -1, VK_HOME
, 1, -1 }
1508 hwnd
= create_listview_control(0);
1510 for (i
=0;i
<items
;i
++) {
1511 insert_item(hwnd
, 0);
1514 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1516 expect(items
,item_count
);
1519 task
= task_list
[i
];
1521 /* deselect all items */
1522 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1523 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1525 /* set initial position */
1526 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, (task
.initPos
== -1 ? item_count
-1 : task
.initPos
));
1527 ListView_SetItemState(hwnd
,(task
.initPos
== -1 ? item_count
-1 : task
.initPos
),LVIS_SELECTED
,LVIS_SELECTED
);
1529 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1531 ok(selected_count
== 1, "There should be only one selected item at the beginning (is %d)\n",selected_count
);
1533 /* Set SHIFT key pressed */
1534 GetKeyboardState(kstate
);
1535 kstate
[VK_SHIFT
]=0x80;
1536 SetKeyboardState(kstate
);
1538 for (j
=1;j
<=(task
.count
== -1 ? item_count
: task
.count
);j
++) {
1539 r
= SendMessage(hwnd
, WM_KEYDOWN
, task
.loopVK
, 0);
1541 r
= SendMessage(hwnd
, WM_KEYUP
, task
.loopVK
, 0);
1545 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1547 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
);
1549 /* Set SHIFT key released */
1550 GetKeyboardState(kstate
);
1551 kstate
[VK_SHIFT
]=0x00;
1552 SetKeyboardState(kstate
);
1554 DestroyWindow(hwnd
);
1556 /* make multiple selection, then switch to LVS_SINGLESEL */
1557 hwnd
= create_listview_control(0);
1558 for (i
=0;i
<items
;i
++) {
1559 insert_item(hwnd
, 0);
1561 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1562 expect(items
,item_count
);
1563 /* deselect all items */
1564 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1565 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1567 ListView_SetItemState(hwnd
, i
, LVIS_SELECTED
, LVIS_SELECTED
);
1570 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1572 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1576 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1577 ok(!(style
& LVS_SINGLESEL
), "LVS_SINGLESEL isn't expected\n");
1578 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SINGLESEL
);
1579 /* check that style is accepted */
1580 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1581 ok(style
& LVS_SINGLESEL
, "LVS_SINGLESEL expected\n");
1584 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1585 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1587 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1589 SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1592 /* select one more */
1593 ListView_SetItemState(hwnd
, 3, LVIS_SELECTED
, LVIS_SELECTED
);
1596 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1597 ok(!(r
& LVIS_SELECTED
), "Expected item %d to be unselected\n", i
);
1599 r
= ListView_GetItemState(hwnd
, 3, LVIS_SELECTED
);
1600 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1602 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1604 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1608 DestroyWindow(hwnd
);
1611 static void test_subitem_rect(void)
1618 /* test LVM_GETSUBITEMRECT for header */
1619 hwnd
= create_listview_control(0);
1620 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1621 /* add some columns */
1622 memset(&col
, 0, sizeof(LVCOLUMN
));
1623 col
.mask
= LVCF_WIDTH
;
1626 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1630 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 1, (LPARAM
)&col
);
1634 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 2, (LPARAM
)&col
);
1636 /* item = -1 means header, subitem index is 1 based */
1637 rect
.left
= LVIR_BOUNDS
;
1639 rect
.right
= rect
.bottom
= 0;
1640 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1643 rect
.left
= LVIR_BOUNDS
;
1645 rect
.right
= rect
.bottom
= 0;
1646 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1648 ok(r
!= 0, "Expected not-null LRESULT\n");
1649 expect(100, rect
.left
);
1650 expect(250, rect
.right
);
1652 expect(3, rect
.top
);
1654 rect
.left
= LVIR_BOUNDS
;
1656 rect
.right
= rect
.bottom
= 0;
1657 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1659 ok(r
!= 0, "Expected not-null LRESULT\n");
1660 expect(250, rect
.left
);
1661 expect(450, rect
.right
);
1663 expect(3, rect
.top
);
1665 DestroyWindow(hwnd
);
1667 /* try it for non LVS_REPORT style */
1668 hwnd
= CreateWindow("SysListView32", "Test", LVS_ICON
, 0, 0, 100, 100, NULL
, NULL
,
1669 GetModuleHandle(NULL
), 0);
1670 rect
.left
= LVIR_BOUNDS
;
1672 rect
.right
= rect
.bottom
= -10;
1673 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1674 ok(r
== 0, "Expected not-null LRESULT\n");
1675 /* rect is unchanged */
1676 expect(0, rect
.left
);
1677 expect(-10, rect
.right
);
1678 expect(1, rect
.top
);
1679 expect(-10, rect
.bottom
);
1680 DestroyWindow(hwnd
);
1683 /* comparison callback for test_sorting */
1684 static INT WINAPI
test_CallBackCompare(LPARAM first
, LPARAM second
, LPARAM lParam
)
1686 if (first
== second
) return 0;
1687 return (first
> second
? 1 : -1);
1690 static void test_sorting(void)
1696 static CHAR names
[][5] = {"A", "B", "C", "D", "0"};
1699 hwnd
= create_listview_control(0);
1700 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1702 /* insert some items */
1703 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
1704 item
.state
= LVIS_SELECTED
;
1708 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1711 item
.mask
= LVIF_PARAM
;
1715 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1718 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
1719 item
.state
= LVIS_SELECTED
;
1723 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1726 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1729 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1732 r
= SendMessage(hwnd
, LVM_SORTITEMS
, 0, (LPARAM
)test_CallBackCompare
);
1735 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1737 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1739 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 0, LVIS_SELECTED
);
1741 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 1, LVIS_SELECTED
);
1742 expect(LVIS_SELECTED
, r
);
1743 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 2, LVIS_SELECTED
);
1744 expect(LVIS_SELECTED
, r
);
1746 DestroyWindow(hwnd
);
1748 /* switch to LVS_SORTASCENDING when some items added */
1749 hwnd
= create_listview_control(0);
1750 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1752 item
.mask
= LVIF_TEXT
;
1755 item
.pszText
= names
[1];
1756 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1759 item
.mask
= LVIF_TEXT
;
1762 item
.pszText
= names
[2];
1763 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1766 item
.mask
= LVIF_TEXT
;
1769 item
.pszText
= names
[0];
1770 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1773 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1774 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SORTASCENDING
);
1775 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1776 ok(style
& LVS_SORTASCENDING
, "Expected LVS_SORTASCENDING to be set\n");
1778 /* no sorting performed when switched to LVS_SORTASCENDING */
1779 item
.mask
= LVIF_TEXT
;
1781 item
.pszText
= buff
;
1782 item
.cchTextMax
= sizeof(buff
);
1783 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1785 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
1788 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1790 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
1793 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1795 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
1797 /* adding new item doesn't resort list */
1798 item
.mask
= LVIF_TEXT
;
1801 item
.pszText
= names
[3];
1802 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1805 item
.mask
= LVIF_TEXT
;
1807 item
.pszText
= buff
;
1808 item
.cchTextMax
= sizeof(buff
);
1809 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1811 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
1814 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1816 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
1819 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1821 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
1824 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1826 ok(lstrcmp(buff
, names
[3]) == 0, "Expected '%s', got '%s'\n", names
[3], buff
);
1828 /* corner case - item should be placed at first position */
1829 item
.mask
= LVIF_TEXT
;
1832 item
.pszText
= names
[4];
1833 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1837 item
.pszText
= buff
;
1838 item
.cchTextMax
= sizeof(buff
);
1839 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1841 ok(lstrcmp(buff
, names
[4]) == 0, "Expected '%s', got '%s'\n", names
[4], buff
);
1844 item
.pszText
= buff
;
1845 item
.cchTextMax
= sizeof(buff
);
1846 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1848 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
1851 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1853 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
1856 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1858 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
1861 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1863 ok(lstrcmp(buff
, names
[3]) == 0, "Expected '%s', got '%s'\n", names
[3], buff
);
1865 DestroyWindow(hwnd
);
1868 static void test_ownerdata(void)
1871 LONG_PTR style
, ret
;
1875 /* it isn't possible to set LVS_OWNERDATA after creation */
1876 hwnd
= create_listview_control(0);
1877 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1878 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1879 ok(!(style
& LVS_OWNERDATA
) && style
, "LVS_OWNERDATA isn't expected\n");
1881 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1883 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1884 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1885 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1886 "try to switch to LVS_OWNERDATA seq", FALSE
);
1888 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1889 ok(!(style
& LVS_OWNERDATA
), "LVS_OWNERDATA isn't expected\n");
1890 DestroyWindow(hwnd
);
1892 /* try to set LVS_OWNERDATA after creation just having it */
1893 hwnd
= create_listview_control(LVS_OWNERDATA
);
1894 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1895 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1896 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1898 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1900 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1901 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1902 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1903 "try to switch to LVS_OWNERDATA seq", FALSE
);
1904 DestroyWindow(hwnd
);
1906 /* try to remove LVS_OWNERDATA after creation just having it */
1907 hwnd
= create_listview_control(LVS_OWNERDATA
);
1908 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1909 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1910 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1912 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1914 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
& ~LVS_OWNERDATA
);
1915 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1916 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1917 "try to switch to LVS_OWNERDATA seq", FALSE
);
1918 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1919 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1920 DestroyWindow(hwnd
);
1922 /* try select an item */
1923 hwnd
= create_listview_control(LVS_OWNERDATA
);
1924 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1925 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1926 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1927 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1929 memset(&item
, 0, sizeof(item
));
1930 item
.stateMask
= LVIS_SELECTED
;
1931 item
.state
= LVIS_SELECTED
;
1932 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
1934 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1936 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1938 DestroyWindow(hwnd
);
1940 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
1941 hwnd
= create_listview_control(LVS_OWNERDATA
);
1942 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1943 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1944 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1945 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1947 memset(&item
, 0, sizeof(item
));
1948 item
.mask
= LVIF_STATE
;
1950 item
.stateMask
= LVIS_SELECTED
;
1951 item
.state
= LVIS_SELECTED
;
1952 res
= SendMessageA(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
1954 DestroyWindow(hwnd
);
1957 static void test_norecompute(void)
1959 static CHAR testA
[] = "test";
1965 /* self containing control */
1966 hwnd
= create_listview_control(0);
1967 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1968 memset(&item
, 0, sizeof(item
));
1969 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
1971 item
.stateMask
= LVIS_SELECTED
;
1972 item
.state
= LVIS_SELECTED
;
1973 item
.pszText
= testA
;
1974 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
1976 /* retrieve with LVIF_NORECOMPUTE */
1977 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
1979 item
.pszText
= buff
;
1980 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
1981 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
1983 ok(lstrcmp(buff
, testA
) == 0, "Expected (%s), got (%s)\n", testA
, buff
);
1985 item
.mask
= LVIF_TEXT
;
1987 item
.pszText
= LPSTR_TEXTCALLBACK
;
1988 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
1991 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
1993 item
.pszText
= buff
;
1994 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
1996 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1997 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
1999 ok(item
.pszText
== LPSTR_TEXTCALLBACK
, "Expected (%p), got (%p)\n",
2000 LPSTR_TEXTCALLBACK
, (VOID
*)item
.pszText
);
2001 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "retrieve with LVIF_NORECOMPUTE seq", FALSE
);
2003 DestroyWindow(hwnd
);
2006 hwnd
= create_listview_control(LVS_OWNERDATA
);
2007 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2009 item
.mask
= LVIF_STATE
;
2010 item
.stateMask
= LVIS_SELECTED
;
2011 item
.state
= LVIS_SELECTED
;
2013 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
2016 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
2018 item
.pszText
= buff
;
2019 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
2020 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2021 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
2023 ok(item
.pszText
== LPSTR_TEXTCALLBACK
, "Expected (%p), got (%p)\n",
2024 LPSTR_TEXTCALLBACK
, (VOID
*)item
.pszText
);
2025 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE
);
2027 DestroyWindow(hwnd
);
2030 static void test_nosortheader(void)
2035 hwnd
= create_listview_control(0);
2036 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2038 header
= (HWND
)SendMessageA(hwnd
, LVM_GETHEADER
, 0, 0);
2039 ok(IsWindow(header
), "header expected\n");
2041 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2042 ok(style
& HDS_BUTTONS
, "expected header to have HDS_BUTTONS\n");
2044 style
= GetWindowLongPtr(hwnd
, GWL_STYLE
);
2045 SetWindowLongPtr(hwnd
, GWL_STYLE
, style
| LVS_NOSORTHEADER
);
2046 /* HDS_BUTTONS retained */
2047 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2048 ok(style
& HDS_BUTTONS
, "expected header to retain HDS_BUTTONS\n");
2050 DestroyWindow(hwnd
);
2052 /* create with LVS_NOSORTHEADER */
2053 hwnd
= create_listview_control(LVS_NOSORTHEADER
);
2054 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2056 header
= (HWND
)SendMessageA(hwnd
, LVM_GETHEADER
, 0, 0);
2057 ok(IsWindow(header
), "header expected\n");
2059 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2060 ok(!(style
& HDS_BUTTONS
), "expected header to have no HDS_BUTTONS\n");
2062 style
= GetWindowLongPtr(hwnd
, GWL_STYLE
);
2063 SetWindowLongPtr(hwnd
, GWL_STYLE
, style
& ~LVS_NOSORTHEADER
);
2064 /* not changed here */
2065 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2066 ok(!(style
& HDS_BUTTONS
), "expected header to have no HDS_BUTTONS\n");
2068 DestroyWindow(hwnd
);
2071 START_TEST(listview
)
2074 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
2076 hComctl32
= GetModuleHandleA("comctl32.dll");
2077 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
2078 if (pInitCommonControlsEx
)
2080 INITCOMMONCONTROLSEX iccex
;
2081 iccex
.dwSize
= sizeof(iccex
);
2082 iccex
.dwICC
= ICC_LISTVIEW_CLASSES
;
2083 pInitCommonControlsEx(&iccex
);
2086 InitCommonControls();
2088 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2090 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2091 hwndparent
= create_parent_window();
2092 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent window", TRUE
);
2093 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2101 test_icon_spacing();
2104 test_item_position();
2108 test_subitem_rect();
2112 test_nosortheader();