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
},
171 static const struct message ownderdata_select_focus_parent_seq
[] = {
172 { WM_NOTIFY
, sent
|id
, 0, 0, LVN_ITEMCHANGED
},
173 { WM_NOTIFY
, sent
|id
, 0, 0, LVN_GETDISPINFOA
},
177 static const struct message textcallback_set_again_parent_seq
[] = {
178 { WM_NOTIFY
, sent
|id
, 0, 0, LVN_ITEMCHANGING
},
179 { WM_NOTIFY
, sent
|id
, 0, 0, LVN_ITEMCHANGED
},
183 static const struct message single_getdispinfo_parent_seq
[] = {
184 { WM_NOTIFY
, sent
|id
, 0, 0, LVN_GETDISPINFOA
},
188 static const struct message getitemposition_seq1
[] = {
189 { LVM_GETITEMPOSITION
, sent
|id
, 0, 0, LISTVIEW_ID
},
193 static const struct message getitemposition_seq2
[] = {
194 { LVM_GETITEMPOSITION
, sent
|id
, 0, 0, LISTVIEW_ID
},
195 { HDM_GETITEMRECT
, sent
|id
, 0, 0, HEADER_ID
},
204 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
206 static LONG defwndproc_counter
= 0;
210 msg
.message
= message
;
211 msg
.flags
= sent
|wparam
|lparam
;
212 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
215 if (message
== WM_NOTIFY
&& lParam
) msg
.id
= ((NMHDR
*)lParam
)->code
;
217 /* log system messages, except for painting */
218 if (message
< WM_USER
&&
219 message
!= WM_PAINT
&&
220 message
!= WM_ERASEBKGND
&&
221 message
!= WM_NCPAINT
&&
222 message
!= WM_NCHITTEST
&&
223 message
!= WM_GETTEXT
&&
224 message
!= WM_GETICON
&&
225 message
!= WM_DEVICECHANGE
)
227 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
229 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
231 add_message(sequences
, PARENT_FULL_SEQ_INDEX
, &msg
);
233 defwndproc_counter
++;
234 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
235 defwndproc_counter
--;
240 static BOOL
register_parent_wnd_class(void)
245 cls
.lpfnWndProc
= parent_wnd_proc
;
248 cls
.hInstance
= GetModuleHandleA(NULL
);
250 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
251 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
252 cls
.lpszMenuName
= NULL
;
253 cls
.lpszClassName
= "Listview test parent class";
254 return RegisterClassA(&cls
);
257 static HWND
create_parent_window(void)
259 if (!register_parent_wnd_class())
262 return CreateWindowEx(0, "Listview test parent class",
263 "Listview test parent window",
264 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
265 WS_MAXIMIZEBOX
| WS_VISIBLE
,
267 GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
270 static LRESULT WINAPI
listview_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
272 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
273 static LONG defwndproc_counter
= 0;
277 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
279 /* some debug output for style changing */
280 if ((message
== WM_STYLECHANGING
||
281 message
== WM_STYLECHANGED
) && lParam
)
283 STYLESTRUCT
*style
= (STYLESTRUCT
*)lParam
;
284 trace("\told style: 0x%08x, new style: 0x%08x\n", style
->styleOld
, style
->styleNew
);
287 msg
.message
= message
;
288 msg
.flags
= sent
|wparam
|lparam
;
289 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
292 msg
.id
= LISTVIEW_ID
;
293 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
295 defwndproc_counter
++;
296 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
297 defwndproc_counter
--;
301 static HWND
create_listview_control(DWORD style
)
303 struct subclass_info
*info
;
307 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
311 GetClientRect(hwndparent
, &rect
);
312 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
313 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| LVS_REPORT
| style
,
314 0, 0, rect
.right
, rect
.bottom
,
315 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
316 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
320 HeapFree(GetProcessHeap(), 0, info
);
324 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
325 (LONG_PTR
)listview_subclass_proc
);
326 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
331 static HWND
create_custom_listview_control(DWORD style
)
333 struct subclass_info
*info
;
337 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
341 GetClientRect(hwndparent
, &rect
);
342 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
343 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
344 0, 0, rect
.right
, rect
.bottom
,
345 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
346 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
350 HeapFree(GetProcessHeap(), 0, info
);
354 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
355 (LONG_PTR
)listview_subclass_proc
);
356 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
361 static LRESULT WINAPI
header_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
363 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
364 static LONG defwndproc_counter
= 0;
368 trace("header: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
370 msg
.message
= message
;
371 msg
.flags
= sent
|wparam
|lparam
;
372 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
376 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
378 defwndproc_counter
++;
379 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
380 defwndproc_counter
--;
384 static HWND
subclass_header(HWND hwndListview
)
386 struct subclass_info
*info
;
389 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
393 hwnd
= ListView_GetHeader(hwndListview
);
394 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
395 (LONG_PTR
)header_subclass_proc
);
396 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
401 /* Performs a single LVM_HITTEST test */
402 static void test_lvm_hittest(HWND hwnd
, INT x
, INT y
, INT item
, UINT flags
,
403 BOOL todo_item
, BOOL todo_flags
, int line
)
412 trace("hittesting pt=(%d,%d)\n", lpht
.pt
.x
, lpht
.pt
.y
);
413 ret
= SendMessage(hwnd
, LVM_HITTEST
, 0, (LPARAM
)&lpht
);
419 ok_(__FILE__
, line
)(ret
== item
, "Expected %d item, got %d\n", item
, ret
);
420 ok_(__FILE__
, line
)(lpht
.iItem
== item
, "Expected %d item, got %d\n", item
, lpht
.iItem
);
421 ok_(__FILE__
, line
)(lpht
.iSubItem
== 10, "Expected subitem not overwrited\n");
426 ok_(__FILE__
, line
)(ret
== item
, "Expected %d item, got %d\n", item
, ret
);
427 ok_(__FILE__
, line
)(lpht
.iItem
== item
, "Expected %d item, got %d\n", item
, lpht
.iItem
);
428 ok_(__FILE__
, line
)(lpht
.iSubItem
== 10, "Expected subitem not overwrited\n");
434 ok_(__FILE__
, line
)(lpht
.flags
== flags
, "Expected flags %x, got %x\n", flags
, lpht
.flags
);
437 ok_(__FILE__
, line
)(lpht
.flags
== flags
, "Expected flags %x, got %x\n", flags
, lpht
.flags
);
440 /* Performs a single LVM_SUBITEMHITTEST test */
441 static void test_lvm_subitemhittest(HWND hwnd
, INT x
, INT y
, INT item
, INT subitem
, UINT flags
,
442 BOOL todo_item
, BOOL todo_subitem
, BOOL todo_flags
, int line
)
450 trace("subhittesting pt=(%d,%d)\n", lpht
.pt
.x
, lpht
.pt
.y
);
451 ret
= SendMessage(hwnd
, LVM_SUBITEMHITTEST
, 0, (LPARAM
)&lpht
);
457 ok_(__FILE__
, line
)(ret
== item
, "Expected %d item, got %d\n", item
, ret
);
458 ok_(__FILE__
, line
)(lpht
.iItem
== item
, "Expected %d item, got %d\n", item
, lpht
.iItem
);
463 ok_(__FILE__
, line
)(ret
== item
, "Expected %d item, got %d\n", item
, ret
);
464 ok_(__FILE__
, line
)(lpht
.iItem
== item
, "Expected %d item, got %d\n", item
, lpht
.iItem
);
470 ok_(__FILE__
, line
)(lpht
.iSubItem
== subitem
, "Expected subitem %d, got %d\n", subitem
, lpht
.iSubItem
);
473 ok_(__FILE__
, line
)(lpht
.iSubItem
== subitem
, "Expected subitem %d, got %d\n", subitem
, lpht
.iSubItem
);
478 ok_(__FILE__
, line
)(lpht
.flags
== flags
, "Expected flags %x, got %x\n", flags
, lpht
.flags
);
481 ok_(__FILE__
, line
)(lpht
.flags
== flags
, "Expected flags %x, got %x\n", flags
, lpht
.flags
);
484 static void test_images(void)
492 static CHAR hello
[] = "hello";
494 himl
= ImageList_Create(40, 40, 0, 4, 4);
495 ok(himl
!= NULL
, "failed to create imagelist\n");
497 hbmp
= CreateBitmap(40, 40, 1, 1, NULL
);
498 ok(hbmp
!= NULL
, "failed to create bitmap\n");
500 r
= ImageList_Add(himl
, hbmp
, 0);
501 ok(r
== 0, "should be zero\n");
503 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED
,
504 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
505 ok(hwnd
!= NULL
, "failed to create listview window\n");
507 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0,
508 LVS_EX_UNDERLINEHOT
| LVS_EX_FLATSB
| LVS_EX_ONECLICKACTIVATE
);
510 ok(r
== 0, "should return zero\n");
512 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)himl
);
513 ok(r
== 0, "should return zero\n");
515 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELONG(100,50));
516 /* returns dimensions */
518 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
519 ok(r
== 0, "should be zero items\n");
521 item
.mask
= LVIF_IMAGE
| LVIF_TEXT
;
526 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
527 ok(r
== -1, "should fail\n");
530 item
.pszText
= hello
;
531 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
532 ok(r
== 0, "should not fail\n");
534 memset(&r1
, 0, sizeof r1
);
536 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r1
);
538 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
539 ok(r
== TRUE
, "should not fail\n");
542 item
.pszText
= hello
;
543 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
544 ok(r
== 0, "should not fail\n");
546 memset(&r2
, 0, sizeof r2
);
548 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r2
);
550 ok(!memcmp(&r1
, &r2
, sizeof r1
), "rectangle should be the same\n");
555 static void test_checkboxes(void)
560 static CHAR text
[] = "Text",
564 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
565 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
566 ok(hwnd
!= NULL
, "failed to create listview window\n");
568 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
569 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
570 item
.stateMask
= 0xffff;
575 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
576 ok(r
== 0, "ret %d\n", r
);
579 item
.mask
= LVIF_STATE
;
580 item
.stateMask
= 0xffff;
581 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
582 ok(item
.state
== 0xfccc, "state %x\n", item
.state
);
584 /* Don't set LVIF_STATE */
585 item
.mask
= LVIF_TEXT
;
586 item
.stateMask
= 0xffff;
591 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
592 ok(r
== 1, "ret %d\n", r
);
595 item
.mask
= LVIF_STATE
;
596 item
.stateMask
= 0xffff;
597 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
598 ok(item
.state
== 0, "state %x\n", item
.state
);
600 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
601 ok(r
== 0, "should return zero\n");
603 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
605 item
.mask
= LVIF_STATE
;
606 item
.stateMask
= 0xffff;
607 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
608 ok(item
.state
== 0x1ccc, "state %x\n", item
.state
);
610 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
612 item
.mask
= LVIF_TEXT
;
614 item
.pszText
= text2
;
615 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
616 ok(r
== 2, "ret %d\n", r
);
619 item
.mask
= LVIF_STATE
;
620 item
.stateMask
= 0xffff;
621 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
622 ok(item
.state
== 0x1000, "state %x\n", item
.state
);
624 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
626 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
627 item
.stateMask
= 0xffff;
629 item
.pszText
= text3
;
630 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
631 ok(r
== 3, "ret %d\n", r
);
634 item
.mask
= LVIF_STATE
;
635 item
.stateMask
= 0xffff;
636 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
637 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
639 /* Set an item's state to checked */
641 item
.mask
= LVIF_STATE
;
642 item
.stateMask
= 0xf000;
644 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
647 item
.mask
= LVIF_STATE
;
648 item
.stateMask
= 0xffff;
649 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
650 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
652 /* Check that only the bits we asked for are returned,
653 * and that all the others are set to zero
656 item
.mask
= LVIF_STATE
;
657 item
.stateMask
= 0xf000;
659 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
660 ok(item
.state
== 0x2000, "state %x\n", item
.state
);
662 /* Set the style again and check that doesn't change an item's state */
663 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
664 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
667 item
.mask
= LVIF_STATE
;
668 item
.stateMask
= 0xffff;
669 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
670 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
672 /* Unsetting the checkbox extended style doesn't change an item's state */
673 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, 0);
674 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
677 item
.mask
= LVIF_STATE
;
678 item
.stateMask
= 0xffff;
679 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
680 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
682 /* Now setting the style again will change an item's state */
683 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
684 ok(r
== 0, "ret %x\n", r
);
687 item
.mask
= LVIF_STATE
;
688 item
.stateMask
= 0xffff;
689 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
690 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
692 /* Toggle checkbox tests (bug 9934) */
693 memset (&item
, 0xcc, sizeof(item
));
694 item
.mask
= LVIF_STATE
;
697 item
.state
= LVIS_FOCUSED
;
698 item
.stateMask
= LVIS_FOCUSED
;
699 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
703 item
.mask
= LVIF_STATE
;
704 item
.stateMask
= 0xffff;
705 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
706 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
708 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
710 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
714 item
.mask
= LVIF_STATE
;
715 item
.stateMask
= 0xffff;
716 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
717 ok(item
.state
== 0x2aab, "state %x\n", item
.state
);
719 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
721 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
725 item
.mask
= LVIF_STATE
;
726 item
.stateMask
= 0xffff;
727 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
728 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
733 static void insert_column(HWND hwnd
, int idx
)
738 memset(&column
, 0xcc, sizeof(column
));
739 column
.mask
= LVCF_SUBITEM
;
740 column
.iSubItem
= idx
;
742 rc
= ListView_InsertColumn(hwnd
, idx
, &column
);
746 static void insert_item(HWND hwnd
, int idx
)
748 static CHAR text
[] = "foo";
753 memset(&item
, 0xcc, sizeof (item
));
754 item
.mask
= LVIF_TEXT
;
759 rc
= ListView_InsertItem(hwnd
, &item
);
763 static void test_items(void)
765 const LPARAM lparamTest
= 0x42;
769 static CHAR text
[] = "Text";
771 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
772 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
773 ok(hwnd
!= NULL
, "failed to create listview window\n");
776 * Test setting/getting item params
779 /* Set up two columns */
780 insert_column(hwnd
, 0);
781 insert_column(hwnd
, 1);
783 /* LVIS_SELECTED with zero stateMask */
785 memset (&item
, 0, sizeof (item
));
786 item
.mask
= LVIF_STATE
;
787 item
.state
= LVIS_SELECTED
;
791 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
792 ok(r
== 0, "ret %d\n", r
);
794 memset (&item
, 0xcc, sizeof (item
));
795 item
.mask
= LVIF_STATE
;
796 item
.stateMask
= LVIS_SELECTED
;
800 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
801 ok(r
!= 0, "ret %d\n", r
);
802 ok(item
.state
& LVIS_SELECTED
, "Expected LVIS_SELECTED\n");
803 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
805 /* LVIS_SELECTED with zero stateMask */
807 memset (&item
, 0, sizeof (item
));
808 item
.mask
= LVIF_STATE
;
809 item
.state
= LVIS_FOCUSED
;
813 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
814 ok(r
== 0, "ret %d\n", r
);
816 memset (&item
, 0xcc, sizeof (item
));
817 item
.mask
= LVIF_STATE
;
818 item
.stateMask
= LVIS_FOCUSED
;
822 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
823 ok(r
!= 0, "ret %d\n", r
);
824 ok(item
.state
& LVIS_FOCUSED
, "Expected LVIS_FOCUSED\n");
825 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
827 /* LVIS_CUT with LVIS_FOCUSED stateMask */
829 memset (&item
, 0, sizeof (item
));
830 item
.mask
= LVIF_STATE
;
831 item
.state
= LVIS_CUT
;
832 item
.stateMask
= LVIS_FOCUSED
;
835 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
836 ok(r
== 0, "ret %d\n", r
);
838 memset (&item
, 0xcc, sizeof (item
));
839 item
.mask
= LVIF_STATE
;
840 item
.stateMask
= LVIS_CUT
;
844 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
845 ok(r
!= 0, "ret %d\n", r
);
846 ok(item
.state
& LVIS_CUT
, "Expected LVIS_CUT\n");
847 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
849 /* Insert an item with just a param */
850 memset (&item
, 0xcc, sizeof (item
));
851 item
.mask
= LVIF_PARAM
;
854 item
.lParam
= lparamTest
;
855 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
856 ok(r
== 0, "ret %d\n", r
);
858 /* Test getting of the param */
859 memset (&item
, 0xcc, sizeof (item
));
860 item
.mask
= LVIF_PARAM
;
863 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
864 ok(r
!= 0, "ret %d\n", r
);
865 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
867 /* Set up a subitem */
868 memset (&item
, 0xcc, sizeof (item
));
869 item
.mask
= LVIF_TEXT
;
873 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
874 ok(r
!= 0, "ret %d\n", r
);
876 /* Query param from subitem: returns main item param */
877 memset (&item
, 0xcc, sizeof (item
));
878 item
.mask
= LVIF_PARAM
;
881 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
882 ok(r
!= 0, "ret %d\n", r
);
883 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
885 /* Set up param on first subitem: no effect */
886 memset (&item
, 0xcc, sizeof (item
));
887 item
.mask
= LVIF_PARAM
;
890 item
.lParam
= lparamTest
+1;
891 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
892 ok(r
== 0, "ret %d\n", r
);
894 /* Query param from subitem again: should still return main item param */
895 memset (&item
, 0xcc, sizeof (item
));
896 item
.mask
= LVIF_PARAM
;
899 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
900 ok(r
!= 0, "ret %d\n", r
);
901 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
903 /**** Some tests of state highlighting ****/
904 memset (&item
, 0xcc, sizeof (item
));
905 item
.mask
= LVIF_STATE
;
908 item
.state
= LVIS_SELECTED
;
909 item
.stateMask
= LVIS_SELECTED
| LVIS_DROPHILITED
;
910 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
911 ok(r
!= 0, "ret %d\n", r
);
913 item
.state
= LVIS_DROPHILITED
;
914 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
915 ok(r
!= 0, "ret %d\n", r
);
917 memset (&item
, 0xcc, sizeof (item
));
918 item
.mask
= LVIF_STATE
;
922 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
923 ok(r
!= 0, "ret %d\n", r
);
924 ok(item
.state
== LVIS_SELECTED
, "got state %x, expected %x\n", item
.state
, LVIS_SELECTED
);
926 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
927 ok(r
!= 0, "ret %d\n", r
);
928 todo_wine
ok(item
.state
== LVIS_DROPHILITED
, "got state %x, expected %x\n", item
.state
, LVIS_DROPHILITED
);
930 /* some notnull but meaningless masks */
931 memset (&item
, 0, sizeof(item
));
932 item
.mask
= LVIF_NORECOMPUTE
;
935 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
936 ok(r
!= 0, "ret %d\n", r
);
937 memset (&item
, 0, sizeof(item
));
938 item
.mask
= LVIF_DI_SETITEM
;
941 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
942 ok(r
!= 0, "ret %d\n", r
);
944 /* set text to callback value already having it */
945 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
947 memset (&item
, 0, sizeof (item
));
948 item
.mask
= LVIF_TEXT
;
949 item
.pszText
= LPSTR_TEXTCALLBACK
;
951 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
952 ok(r
== 0, "ret %d\n", r
);
953 memset (&item
, 0, sizeof (item
));
955 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
957 item
.pszText
= LPSTR_TEXTCALLBACK
;
958 r
= SendMessage(hwnd
, LVM_SETITEMTEXT
, 0 , (LPARAM
) &item
);
961 ok_sequence(sequences
, PARENT_SEQ_INDEX
, textcallback_set_again_parent_seq
,
962 "check callback text comparison rule", TRUE
);
967 static void test_columns(void)
969 HWND hwnd
, hwndheader
;
974 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
975 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
976 ok(hwnd
!= NULL
, "failed to create listview window\n");
978 /* Add a column with no mask */
979 memset(&column
, 0xcc, sizeof(column
));
981 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
982 ok(rc
==0, "Inserting column with no mask failed with %d\n", rc
);
984 /* Check its width */
985 rc
= ListView_GetColumnWidth(hwnd
, 0);
987 broken(rc
==0), /* win9x */
988 "Inserting column with no mask failed to set width to 10 with %d\n", rc
);
992 /* LVM_GETCOLUMNORDERARRAY */
993 hwnd
= create_listview_control(0);
994 hwndheader
= subclass_header(hwnd
);
996 memset(&column
, 0, sizeof(column
));
997 column
.mask
= LVCF_WIDTH
;
999 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
1000 ok(rc
== 0, "Inserting column failed with %d\n", rc
);
1003 rc
= ListView_InsertColumn(hwnd
, 1, &column
);
1004 ok(rc
== 1, "Inserting column failed with %d\n", rc
);
1006 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1008 rc
= SendMessage(hwnd
, LVM_GETCOLUMNORDERARRAY
, 2, (LPARAM
)&order
);
1009 ok(rc
!= 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
1010 ok(order
[0] == 0, "Expected order 0, got %d\n", order
[0]);
1011 ok(order
[1] == 1, "Expected order 1, got %d\n", order
[1]);
1013 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_getorderarray_seq
, "get order array", FALSE
);
1015 DestroyWindow(hwnd
);
1017 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1018 static WNDPROC listviewWndProc
;
1019 static HIMAGELIST test_create_imagelist
;
1021 static LRESULT CALLBACK
create_test_wndproc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1025 if (uMsg
== WM_CREATE
)
1027 LPCREATESTRUCT lpcs
= (LPCREATESTRUCT
)lParam
;
1028 lpcs
->style
|= LVS_REPORT
;
1030 ret
= CallWindowProc(listviewWndProc
, hwnd
, uMsg
, wParam
, lParam
);
1031 if (uMsg
== WM_CREATE
) SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)test_create_imagelist
);
1035 static void test_create(void)
1044 cls
.cbSize
= sizeof(WNDCLASSEX
);
1045 ok(GetClassInfoEx(GetModuleHandle(NULL
), "SysListView32", &cls
), "GetClassInfoEx failed\n");
1046 listviewWndProc
= cls
.lpfnWndProc
;
1047 cls
.lpfnWndProc
= create_test_wndproc
;
1048 cls
.lpszClassName
= "MyListView32";
1049 ok(RegisterClassEx(&cls
), "RegisterClassEx failed\n");
1051 test_create_imagelist
= ImageList_Create(16, 16, 0, 5, 10);
1052 hList
= CreateWindow("MyListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
1053 ok((HIMAGELIST
)SendMessage(hList
, LVM_GETIMAGELIST
, 0, 0) == test_create_imagelist
, "Image list not obtained\n");
1054 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1055 ok(IsWindow(hHeader
) && IsWindowVisible(hHeader
), "Listview not in report mode\n");
1056 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1057 DestroyWindow(hList
);
1059 /* header isn't created on LVS_ICON and LVS_LIST styles */
1060 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
1061 GetModuleHandle(NULL
), 0);
1062 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1063 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1064 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1066 memset(&col
, 0, sizeof(LVCOLUMNA
));
1067 col
.mask
= LVCF_WIDTH
;
1069 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1070 ok(r
== 0, "Expected 0 column's inserted\n");
1071 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1072 ok(IsWindow(hHeader
), "Header should be created\n");
1073 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1074 DestroyWindow(hList
);
1076 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
1077 GetModuleHandle(NULL
), 0);
1078 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1079 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1080 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1082 memset(&col
, 0, sizeof(LVCOLUMNA
));
1083 col
.mask
= LVCF_WIDTH
;
1085 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1086 ok(r
== 0, "Expected 0 column's inserted\n");
1087 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1088 ok(IsWindow(hHeader
), "Header should be created\n");
1089 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1090 DestroyWindow(hList
);
1092 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1093 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
1094 GetModuleHandle(NULL
), 0);
1095 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLongPtr(hList
, GWL_STYLE
) | LVS_REPORT
);
1096 ok(ret
& WS_VISIBLE
, "Style wrong, should have WS_VISIBLE\n");
1097 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1098 ok(IsWindow(hHeader
), "Header should be created\n");
1099 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLong(hList
, GWL_STYLE
) & ~LVS_REPORT
);
1100 ok((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1101 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1102 ok(IsWindow(hHeader
), "Header should be created\n");
1103 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1104 DestroyWindow(hList
);
1106 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1107 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
1108 GetModuleHandle(NULL
), 0);
1109 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
1110 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_LIST
) | LVS_REPORT
);
1111 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_LIST
)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1112 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1113 ok(IsWindow(hHeader
), "Header should be created\n");
1114 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1115 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
1116 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_REPORT
) | LVS_LIST
);
1117 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1118 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1119 ok(IsWindow(hHeader
), "Header should be created\n");
1120 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1121 DestroyWindow(hList
);
1123 /* LVS_REPORT without WS_VISIBLE */
1124 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1125 GetModuleHandle(NULL
), 0);
1126 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1127 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1128 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1130 memset(&col
, 0, sizeof(LVCOLUMNA
));
1131 col
.mask
= LVCF_WIDTH
;
1133 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1134 ok(r
== 0, "Expected 0 column's inserted\n");
1135 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1136 ok(IsWindow(hHeader
), "Header should be created\n");
1137 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1138 DestroyWindow(hList
);
1140 /* LVS_REPORT without WS_VISIBLE, try to show it */
1141 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1142 GetModuleHandle(NULL
), 0);
1143 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1144 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1145 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1146 ShowWindow(hList
, SW_SHOW
);
1147 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1148 ok(IsWindow(hHeader
), "Header should be created\n");
1149 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1150 DestroyWindow(hList
);
1152 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1153 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
|LVS_NOCOLUMNHEADER
|WS_VISIBLE
,
1154 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
1155 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1156 ok(IsWindow(hHeader
), "Header should be created\n");
1157 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1158 /* HDS_DRAGDROP set by default */
1159 ok(GetWindowLongPtr(hHeader
, GWL_STYLE
) & HDS_DRAGDROP
, "Expected header to have HDS_DRAGDROP\n");
1160 DestroyWindow(hList
);
1162 /* setting LVS_EX_HEADERDRAGDROP creates header */
1163 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1164 GetModuleHandle(NULL
), 0);
1165 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1166 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1167 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1168 SendMessage(hList
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_HEADERDRAGDROP
);
1169 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1170 ok(IsWindow(hHeader
), "Header should be created\n");
1171 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1172 DestroyWindow(hList
);
1174 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1175 hList
= create_custom_listview_control(0);
1176 SendMessage(hList
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_HEADERDRAGDROP
);
1177 r
= SendMessage(hList
, LVM_GETEXTENDEDLISTVIEWSTYLE
, 0, 0);
1178 ok(r
& LVS_EX_HEADERDRAGDROP
, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1179 DestroyWindow(hList
);
1181 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1182 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1183 GetModuleHandle(NULL
), 0);
1184 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1185 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1187 rect
.left
= LVIR_BOUNDS
;
1189 rect
.right
= rect
.bottom
= -10;
1190 r
= SendMessage(hList
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1191 ok(r
!= 0, "Expected not-null LRESULT\n");
1193 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1194 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1195 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1197 DestroyWindow(hList
);
1200 static void test_redraw(void)
1202 HWND hwnd
, hwndheader
;
1207 hwnd
= create_listview_control(0);
1208 hwndheader
= subclass_header(hwnd
);
1210 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1212 trace("invalidate & update\n");
1213 InvalidateRect(hwnd
, NULL
, TRUE
);
1215 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, redraw_listview_seq
, "redraw listview", FALSE
);
1217 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1219 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1220 /* 1. Without backbuffer */
1221 res
= ListView_SetBkColor(hwnd
, CLR_NONE
);
1224 hdc
= GetWindowDC(hwndparent
);
1226 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1227 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1228 ok(r
!= 0, "Expected not zero result\n");
1229 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, forward_erasebkgnd_parent_seq
,
1230 "forward WM_ERASEBKGND on CLR_NONE", FALSE
);
1232 res
= ListView_SetBkColor(hwnd
, CLR_DEFAULT
);
1235 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1236 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1237 ok(r
!= 0, "Expected not zero result\n");
1238 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, empty_seq
,
1239 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE
);
1241 /* 2. With backbuffer */
1242 SendMessageA(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_DOUBLEBUFFER
,
1243 LVS_EX_DOUBLEBUFFER
);
1244 res
= ListView_SetBkColor(hwnd
, CLR_NONE
);
1247 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1248 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1249 ok(r
!= 0, "Expected not zero result\n");
1250 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, forward_erasebkgnd_parent_seq
,
1251 "forward WM_ERASEBKGND on CLR_NONE", FALSE
);
1253 res
= ListView_SetBkColor(hwnd
, CLR_DEFAULT
);
1256 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1257 r
= SendMessageA(hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
1258 todo_wine
ok(r
!= 0, "Expected not zero result\n");
1259 ok_sequence(sequences
, PARENT_FULL_SEQ_INDEX
, empty_seq
,
1260 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE
);
1262 ReleaseDC(hwndparent
, hdc
);
1264 DestroyWindow(hwnd
);
1267 static LRESULT WINAPI
cd_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1269 COLORREF clr
, c0ffee
= RGB(0xc0, 0xff, 0xee);
1271 if(msg
== WM_NOTIFY
) {
1272 NMHDR
*nmhdr
= (PVOID
)lp
;
1273 if(nmhdr
->code
== NM_CUSTOMDRAW
) {
1274 NMLVCUSTOMDRAW
*nmlvcd
= (PVOID
)nmhdr
;
1275 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd
->nmcd
.dwDrawStage
);
1276 switch(nmlvcd
->nmcd
.dwDrawStage
) {
1278 SetBkColor(nmlvcd
->nmcd
.hdc
, c0ffee
);
1279 return CDRF_NOTIFYITEMDRAW
;
1280 case CDDS_ITEMPREPAINT
:
1281 nmlvcd
->clrTextBk
= CLR_DEFAULT
;
1282 return CDRF_NOTIFYSUBITEMDRAW
;
1283 case CDDS_ITEMPREPAINT
| CDDS_SUBITEM
:
1284 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1285 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1286 return CDRF_NOTIFYPOSTPAINT
;
1287 case CDDS_ITEMPOSTPAINT
| CDDS_SUBITEM
:
1288 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1289 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1290 return CDRF_DODEFAULT
;
1292 return CDRF_DODEFAULT
;
1296 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
1299 static void test_customdraw(void)
1304 hwnd
= create_listview_control(0);
1306 insert_column(hwnd
, 0);
1307 insert_column(hwnd
, 1);
1308 insert_item(hwnd
, 0);
1310 oldwndproc
= (WNDPROC
)SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
,
1311 (LONG_PTR
)cd_wndproc
);
1313 InvalidateRect(hwnd
, NULL
, TRUE
);
1316 SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
, (LONG_PTR
)oldwndproc
);
1318 DestroyWindow(hwnd
);
1321 static void test_icon_spacing(void)
1323 /* LVM_SETICONSPACING */
1324 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1330 hwnd
= create_custom_listview_control(LVS_ICON
);
1331 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1333 r
= SendMessage(hwnd
, WM_NOTIFYFORMAT
, (WPARAM
)hwndparent
, (LPARAM
)NF_REQUERY
);
1334 expect(NFR_ANSI
, r
);
1336 /* reset the icon spacing to defaults */
1337 SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1339 /* now we can request what the defaults are */
1340 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1344 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1346 trace("test icon spacing\n");
1348 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(20, 30));
1349 ok(r
== MAKELONG(w
, h
) ||
1350 broken(r
== MAKELONG(w
, w
)), /* win98 */
1351 "Expected %d, got %d\n", MAKELONG(w
, h
), r
);
1353 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(25, 35));
1354 expect(MAKELONG(20,30), r
);
1356 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1,-1));
1357 expect(MAKELONG(25,35), r
);
1359 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_icon_spacing_seq
, "test icon spacing seq", FALSE
);
1361 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1362 DestroyWindow(hwnd
);
1365 static void test_color(void)
1367 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1374 COLORREF colors
[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE
, RGB(255,255,255)};
1376 hwnd
= create_listview_control(0);
1377 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1379 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1381 trace("test color seq\n");
1382 for (i
= 0; i
< 4; i
++)
1386 r
= SendMessage(hwnd
, LVM_SETBKCOLOR
, 0, color
);
1388 r
= SendMessage(hwnd
, LVM_GETBKCOLOR
, 0, color
);
1391 r
= SendMessage(hwnd
, LVM_SETTEXTCOLOR
, 0, color
);
1393 r
= SendMessage(hwnd
, LVM_GETTEXTCOLOR
, 0, color
);
1396 r
= SendMessage(hwnd
, LVM_SETTEXTBKCOLOR
, 0, color
);
1398 r
= SendMessage(hwnd
, LVM_GETTEXTBKCOLOR
, 0, color
);
1402 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_color_seq
, "test color seq", FALSE
);
1404 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1405 DestroyWindow(hwnd
);
1408 static void test_item_count(void)
1410 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1418 static CHAR item0text
[] = "item0";
1419 static CHAR item1text
[] = "item1";
1420 static CHAR item2text
[] = "item2";
1422 hwnd
= create_listview_control(0);
1423 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1425 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1427 trace("test item count\n");
1429 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1433 item0
.mask
= LVIF_TEXT
;
1436 item0
.pszText
= item0text
;
1437 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1440 /* [item0, item1] */
1441 item1
.mask
= LVIF_TEXT
;
1444 item1
.pszText
= item1text
;
1445 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1448 /* [item0, item1, item2] */
1449 item2
.mask
= LVIF_TEXT
;
1452 item2
.pszText
= item2text
;
1453 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1456 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1459 /* [item0, item1] */
1460 r
= SendMessage(hwnd
, LVM_DELETEITEM
, 2, 0);
1463 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1467 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
1470 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1474 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1477 /* [item0, item1] */
1478 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1481 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1484 /* [item0, item1, item2] */
1485 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1488 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1491 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_item_count_seq
, "test item count seq", FALSE
);
1493 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1494 DestroyWindow(hwnd
);
1497 static void test_item_position(void)
1499 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1508 static CHAR item0text
[] = "item0";
1509 static CHAR item1text
[] = "item1";
1510 static CHAR item2text
[] = "item2";
1512 hwnd
= create_custom_listview_control(LVS_ICON
);
1513 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1515 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1517 trace("test item position\n");
1520 item0
.mask
= LVIF_TEXT
;
1523 item0
.pszText
= item0text
;
1524 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1527 /* [item0, item1] */
1528 item1
.mask
= LVIF_TEXT
;
1531 item1
.pszText
= item1text
;
1532 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1535 /* [item0, item1, item2] */
1536 item2
.mask
= LVIF_TEXT
;
1539 item2
.pszText
= item2text
;
1540 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1543 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 1, MAKELPARAM(10,5));
1545 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 1, (LPARAM
) &position
);
1547 expect2(10, 5, position
.x
, position
.y
);
1549 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 2, MAKELPARAM(0,0));
1551 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 2, (LPARAM
) &position
);
1553 expect2(0, 0, position
.x
, position
.y
);
1555 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 0, MAKELPARAM(20,20));
1557 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
) &position
);
1559 expect2(20, 20, position
.x
, position
.y
);
1561 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_itempos_seq
, "test item position seq", TRUE
);
1563 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1564 DestroyWindow(hwnd
);
1567 static void test_getorigin(void)
1575 position
.x
= position
.y
= 0;
1577 hwnd
= create_custom_listview_control(LVS_ICON
);
1578 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1579 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1580 trace("test get origin results\n");
1581 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1583 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1584 DestroyWindow(hwnd
);
1586 hwnd
= create_custom_listview_control(LVS_SMALLICON
);
1587 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1588 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1589 trace("test get origin results\n");
1590 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1592 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1593 DestroyWindow(hwnd
);
1595 hwnd
= create_custom_listview_control(LVS_LIST
);
1596 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1597 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1598 trace("test get origin results\n");
1599 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1601 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1602 DestroyWindow(hwnd
);
1604 hwnd
= create_custom_listview_control(LVS_REPORT
);
1605 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1606 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1607 trace("test get origin results\n");
1608 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1610 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1611 DestroyWindow(hwnd
);
1615 static void test_multiselect(void)
1617 typedef struct t_select_task
1628 int i
,j
,item_count
,selected_count
;
1629 static const int items
=5;
1635 static struct t_select_task task_list
[] = {
1636 { "using VK_DOWN", 0, VK_DOWN
, -1, -1 },
1637 { "using VK_UP", -1, VK_UP
, -1, -1 },
1638 { "using VK_END", 0, VK_END
, 1, -1 },
1639 { "using VK_HOME", -1, VK_HOME
, 1, -1 }
1643 hwnd
= create_listview_control(0);
1645 for (i
=0;i
<items
;i
++) {
1646 insert_item(hwnd
, 0);
1649 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1651 expect(items
,item_count
);
1654 task
= task_list
[i
];
1656 /* deselect all items */
1657 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1658 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1660 /* set initial position */
1661 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, (task
.initPos
== -1 ? item_count
-1 : task
.initPos
));
1662 ListView_SetItemState(hwnd
,(task
.initPos
== -1 ? item_count
-1 : task
.initPos
),LVIS_SELECTED
,LVIS_SELECTED
);
1664 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1666 ok(selected_count
== 1, "There should be only one selected item at the beginning (is %d)\n",selected_count
);
1668 /* Set SHIFT key pressed */
1669 GetKeyboardState(kstate
);
1670 kstate
[VK_SHIFT
]=0x80;
1671 SetKeyboardState(kstate
);
1673 for (j
=1;j
<=(task
.count
== -1 ? item_count
: task
.count
);j
++) {
1674 r
= SendMessage(hwnd
, WM_KEYDOWN
, task
.loopVK
, 0);
1676 r
= SendMessage(hwnd
, WM_KEYUP
, task
.loopVK
, 0);
1680 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1682 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
);
1684 /* Set SHIFT key released */
1685 GetKeyboardState(kstate
);
1686 kstate
[VK_SHIFT
]=0x00;
1687 SetKeyboardState(kstate
);
1689 DestroyWindow(hwnd
);
1691 /* make multiple selection, then switch to LVS_SINGLESEL */
1692 hwnd
= create_listview_control(0);
1693 for (i
=0;i
<items
;i
++) {
1694 insert_item(hwnd
, 0);
1696 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1697 expect(items
,item_count
);
1698 /* deselect all items */
1699 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1700 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1702 ListView_SetItemState(hwnd
, i
, LVIS_SELECTED
, LVIS_SELECTED
);
1705 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1707 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1711 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1712 ok(!(style
& LVS_SINGLESEL
), "LVS_SINGLESEL isn't expected\n");
1713 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SINGLESEL
);
1714 /* check that style is accepted */
1715 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1716 ok(style
& LVS_SINGLESEL
, "LVS_SINGLESEL expected\n");
1719 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1720 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1722 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1724 SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1727 /* select one more */
1728 ListView_SetItemState(hwnd
, 3, LVIS_SELECTED
, LVIS_SELECTED
);
1731 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1732 ok(!(r
& LVIS_SELECTED
), "Expected item %d to be unselected\n", i
);
1734 r
= ListView_GetItemState(hwnd
, 3, LVIS_SELECTED
);
1735 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1737 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1739 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1743 /* try to select all on LVS_SINGLESEL */
1744 memset(&item
, 0, sizeof(item
));
1745 item
.stateMask
= LVIS_SELECTED
;
1746 r
= SendMessage(hwnd
, LVM_SETITEMSTATE
, -1, (LPARAM
)&item
);
1748 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1750 item
.stateMask
= LVIS_SELECTED
;
1751 item
.state
= LVIS_SELECTED
;
1752 r
= SendMessage(hwnd
, LVM_SETITEMSTATE
, -1, (LPARAM
)&item
);
1755 r
= ListView_GetSelectedCount(hwnd
);
1757 r
= ListView_GetSelectionMark(hwnd
);
1760 /* try to deselect all on LVS_SINGLESEL */
1761 item
.stateMask
= LVIS_SELECTED
;
1762 item
.state
= LVIS_SELECTED
;
1763 r
= SendMessage(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
1766 item
.stateMask
= LVIS_SELECTED
;
1768 r
= SendMessage(hwnd
, LVM_SETITEMSTATE
, -1, (LPARAM
)&item
);
1770 r
= ListView_GetSelectedCount(hwnd
);
1773 DestroyWindow(hwnd
);
1776 static void test_subitem_rect(void)
1783 /* test LVM_GETSUBITEMRECT for header */
1784 hwnd
= create_listview_control(0);
1785 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1786 /* add some columns */
1787 memset(&col
, 0, sizeof(LVCOLUMN
));
1788 col
.mask
= LVCF_WIDTH
;
1791 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1795 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 1, (LPARAM
)&col
);
1799 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 2, (LPARAM
)&col
);
1801 /* item = -1 means header, subitem index is 1 based */
1802 rect
.left
= LVIR_BOUNDS
;
1804 rect
.right
= rect
.bottom
= 0;
1805 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1808 rect
.left
= LVIR_BOUNDS
;
1810 rect
.right
= rect
.bottom
= 0;
1811 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1813 ok(r
!= 0, "Expected not-null LRESULT\n");
1814 expect(100, rect
.left
);
1815 expect(250, rect
.right
);
1817 expect(3, rect
.top
);
1819 rect
.left
= LVIR_BOUNDS
;
1821 rect
.right
= rect
.bottom
= 0;
1822 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1824 ok(r
!= 0, "Expected not-null LRESULT\n");
1825 expect(250, rect
.left
);
1826 expect(450, rect
.right
);
1828 expect(3, rect
.top
);
1830 /* item LVS_REPORT padding isn't applied to subitems */
1831 insert_item(hwnd
, 0);
1833 rect
.left
= LVIR_BOUNDS
;
1835 rect
.right
= rect
.bottom
= 0;
1836 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, 0, (LPARAM
)&rect
);
1837 ok(r
!= 0, "Expected not-null LRESULT\n");
1838 expect(100, rect
.left
);
1839 expect(250, rect
.right
);
1841 rect
.left
= LVIR_ICON
;
1843 rect
.right
= rect
.bottom
= 0;
1844 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, 0, (LPARAM
)&rect
);
1845 ok(r
!= 0, "Expected not-null LRESULT\n");
1846 /* no icon attached - zero width rectangle, with no left padding */
1847 expect(100, rect
.left
);
1848 expect(100, rect
.right
);
1850 rect
.left
= LVIR_LABEL
;
1852 rect
.right
= rect
.bottom
= 0;
1853 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, 0, (LPARAM
)&rect
);
1854 ok(r
!= 0, "Expected not-null LRESULT\n");
1855 /* same as full LVIR_BOUNDS */
1856 expect(100, rect
.left
);
1857 expect(250, rect
.right
);
1859 DestroyWindow(hwnd
);
1861 /* try it for non LVS_REPORT style */
1862 hwnd
= CreateWindow("SysListView32", "Test", LVS_ICON
, 0, 0, 100, 100, NULL
, NULL
,
1863 GetModuleHandle(NULL
), 0);
1864 rect
.left
= LVIR_BOUNDS
;
1866 rect
.right
= rect
.bottom
= -10;
1867 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1868 ok(r
== 0, "Expected not-null LRESULT\n");
1869 /* rect is unchanged */
1870 expect(0, rect
.left
);
1871 expect(-10, rect
.right
);
1872 expect(1, rect
.top
);
1873 expect(-10, rect
.bottom
);
1874 DestroyWindow(hwnd
);
1877 /* comparison callback for test_sorting */
1878 static INT WINAPI
test_CallBackCompare(LPARAM first
, LPARAM second
, LPARAM lParam
)
1880 if (first
== second
) return 0;
1881 return (first
> second
? 1 : -1);
1884 static void test_sorting(void)
1890 static CHAR names
[][5] = {"A", "B", "C", "D", "0"};
1893 hwnd
= create_listview_control(0);
1894 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1896 /* insert some items */
1897 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
1898 item
.state
= LVIS_SELECTED
;
1902 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1905 item
.mask
= LVIF_PARAM
;
1909 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1912 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
1913 item
.state
= LVIS_SELECTED
;
1917 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1920 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1923 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1926 r
= SendMessage(hwnd
, LVM_SORTITEMS
, 0, (LPARAM
)test_CallBackCompare
);
1929 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1931 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1933 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 0, LVIS_SELECTED
);
1935 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 1, LVIS_SELECTED
);
1936 expect(LVIS_SELECTED
, r
);
1937 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 2, LVIS_SELECTED
);
1938 expect(LVIS_SELECTED
, r
);
1940 DestroyWindow(hwnd
);
1942 /* switch to LVS_SORTASCENDING when some items added */
1943 hwnd
= create_listview_control(0);
1944 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1946 item
.mask
= LVIF_TEXT
;
1949 item
.pszText
= names
[1];
1950 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1953 item
.mask
= LVIF_TEXT
;
1956 item
.pszText
= names
[2];
1957 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1960 item
.mask
= LVIF_TEXT
;
1963 item
.pszText
= names
[0];
1964 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1967 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1968 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SORTASCENDING
);
1969 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1970 ok(style
& LVS_SORTASCENDING
, "Expected LVS_SORTASCENDING to be set\n");
1972 /* no sorting performed when switched to LVS_SORTASCENDING */
1973 item
.mask
= LVIF_TEXT
;
1975 item
.pszText
= buff
;
1976 item
.cchTextMax
= sizeof(buff
);
1977 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1979 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
1982 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1984 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
1987 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1989 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
1991 /* adding new item doesn't resort list */
1992 item
.mask
= LVIF_TEXT
;
1995 item
.pszText
= names
[3];
1996 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1999 item
.mask
= LVIF_TEXT
;
2001 item
.pszText
= buff
;
2002 item
.cchTextMax
= sizeof(buff
);
2003 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2005 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
2008 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2010 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
2013 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2015 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
2018 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2020 ok(lstrcmp(buff
, names
[3]) == 0, "Expected '%s', got '%s'\n", names
[3], buff
);
2022 /* corner case - item should be placed at first position */
2023 item
.mask
= LVIF_TEXT
;
2026 item
.pszText
= names
[4];
2027 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
2031 item
.pszText
= buff
;
2032 item
.cchTextMax
= sizeof(buff
);
2033 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2035 ok(lstrcmp(buff
, names
[4]) == 0, "Expected '%s', got '%s'\n", names
[4], buff
);
2038 item
.pszText
= buff
;
2039 item
.cchTextMax
= sizeof(buff
);
2040 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2042 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
2045 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2047 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
2050 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2052 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
2055 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
2057 ok(lstrcmp(buff
, names
[3]) == 0, "Expected '%s', got '%s'\n", names
[3], buff
);
2059 DestroyWindow(hwnd
);
2062 static void test_ownerdata(void)
2065 LONG_PTR style
, ret
;
2069 /* it isn't possible to set LVS_OWNERDATA after creation */
2070 hwnd
= create_listview_control(0);
2071 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2072 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
2073 ok(!(style
& LVS_OWNERDATA
) && style
, "LVS_OWNERDATA isn't expected\n");
2075 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2077 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
2078 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
2079 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
2080 "try to switch to LVS_OWNERDATA seq", FALSE
);
2082 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
2083 ok(!(style
& LVS_OWNERDATA
), "LVS_OWNERDATA isn't expected\n");
2084 DestroyWindow(hwnd
);
2086 /* try to set LVS_OWNERDATA after creation just having it */
2087 hwnd
= create_listview_control(LVS_OWNERDATA
);
2088 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2089 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
2090 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
2092 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2094 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
2095 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
2096 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
2097 "try to switch to LVS_OWNERDATA seq", FALSE
);
2098 DestroyWindow(hwnd
);
2100 /* try to remove LVS_OWNERDATA after creation just having it */
2101 hwnd
= create_listview_control(LVS_OWNERDATA
);
2102 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2103 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
2104 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
2106 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2108 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
& ~LVS_OWNERDATA
);
2109 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
2110 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
2111 "try to switch to LVS_OWNERDATA seq", FALSE
);
2112 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
2113 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
2114 DestroyWindow(hwnd
);
2116 /* try select an item */
2117 hwnd
= create_listview_control(LVS_OWNERDATA
);
2118 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2119 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
2120 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2121 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
2123 memset(&item
, 0, sizeof(item
));
2124 item
.stateMask
= LVIS_SELECTED
;
2125 item
.state
= LVIS_SELECTED
;
2126 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
2128 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
2130 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
2132 DestroyWindow(hwnd
);
2134 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
2135 hwnd
= create_listview_control(LVS_OWNERDATA
);
2136 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2137 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
2138 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2139 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
2141 memset(&item
, 0, sizeof(item
));
2142 item
.mask
= LVIF_STATE
;
2144 item
.stateMask
= LVIS_SELECTED
;
2145 item
.state
= LVIS_SELECTED
;
2146 res
= SendMessageA(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
2148 DestroyWindow(hwnd
);
2150 /* check notifications after focused/selected changed */
2151 hwnd
= create_listview_control(LVS_OWNERDATA
);
2152 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2153 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
2154 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2156 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2158 memset(&item
, 0, sizeof(item
));
2159 item
.stateMask
= LVIS_SELECTED
;
2160 item
.state
= LVIS_SELECTED
;
2161 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
2164 ok_sequence(sequences
, PARENT_SEQ_INDEX
, ownderdata_select_focus_parent_seq
,
2165 "ownerdata select notification", TRUE
);
2167 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2169 memset(&item
, 0, sizeof(item
));
2170 item
.stateMask
= LVIS_FOCUSED
;
2171 item
.state
= LVIS_FOCUSED
;
2172 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
2175 ok_sequence(sequences
, PARENT_SEQ_INDEX
, ownderdata_select_focus_parent_seq
,
2176 "ownerdata focus notification", TRUE
);
2177 DestroyWindow(hwnd
);
2179 /* check notifications on LVM_GETITEM */
2180 /* zero callback mask */
2181 hwnd
= create_listview_control(LVS_OWNERDATA
);
2182 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2183 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
2184 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2186 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2188 memset(&item
, 0, sizeof(item
));
2189 item
.stateMask
= LVIS_SELECTED
;
2190 item
.mask
= LVIF_STATE
;
2191 res
= SendMessageA(hwnd
, LVM_GETITEMA
, 0, (LPARAM
)&item
);
2194 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
2195 "ownerdata getitem selected state 1", FALSE
);
2197 /* non zero callback mask but not we asking for */
2198 res
= SendMessageA(hwnd
, LVM_SETCALLBACKMASK
, LVIS_OVERLAYMASK
, 0);
2201 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2203 memset(&item
, 0, sizeof(item
));
2204 item
.stateMask
= LVIS_SELECTED
;
2205 item
.mask
= LVIF_STATE
;
2206 res
= SendMessageA(hwnd
, LVM_GETITEMA
, 0, (LPARAM
)&item
);
2209 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
,
2210 "ownerdata getitem selected state 2", FALSE
);
2212 /* LVIS_OVERLAYMASK callback mask, asking for index */
2213 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2215 memset(&item
, 0, sizeof(item
));
2216 item
.stateMask
= LVIS_OVERLAYMASK
;
2217 item
.mask
= LVIF_STATE
;
2218 res
= SendMessageA(hwnd
, LVM_GETITEMA
, 0, (LPARAM
)&item
);
2221 ok_sequence(sequences
, PARENT_SEQ_INDEX
, single_getdispinfo_parent_seq
,
2222 "ownerdata getitem selected state 2", FALSE
);
2224 DestroyWindow(hwnd
);
2227 static void test_norecompute(void)
2229 static CHAR testA
[] = "test";
2235 /* self containing control */
2236 hwnd
= create_listview_control(0);
2237 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2238 memset(&item
, 0, sizeof(item
));
2239 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
2241 item
.stateMask
= LVIS_SELECTED
;
2242 item
.state
= LVIS_SELECTED
;
2243 item
.pszText
= testA
;
2244 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
2246 /* retrieve with LVIF_NORECOMPUTE */
2247 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
2249 item
.pszText
= buff
;
2250 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
2251 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
2253 ok(lstrcmp(buff
, testA
) == 0, "Expected (%s), got (%s)\n", testA
, buff
);
2255 item
.mask
= LVIF_TEXT
;
2257 item
.pszText
= LPSTR_TEXTCALLBACK
;
2258 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
2261 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
2263 item
.pszText
= buff
;
2264 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
2266 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2267 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
2269 ok(item
.pszText
== LPSTR_TEXTCALLBACK
, "Expected (%p), got (%p)\n",
2270 LPSTR_TEXTCALLBACK
, (VOID
*)item
.pszText
);
2271 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "retrieve with LVIF_NORECOMPUTE seq", FALSE
);
2273 DestroyWindow(hwnd
);
2276 hwnd
= create_listview_control(LVS_OWNERDATA
);
2277 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2279 item
.mask
= LVIF_STATE
;
2280 item
.stateMask
= LVIS_SELECTED
;
2281 item
.state
= LVIS_SELECTED
;
2283 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
2286 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
2288 item
.pszText
= buff
;
2289 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
2290 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2291 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
2293 ok(item
.pszText
== LPSTR_TEXTCALLBACK
, "Expected (%p), got (%p)\n",
2294 LPSTR_TEXTCALLBACK
, (VOID
*)item
.pszText
);
2295 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE
);
2297 DestroyWindow(hwnd
);
2300 static void test_nosortheader(void)
2305 hwnd
= create_listview_control(0);
2306 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2308 header
= (HWND
)SendMessageA(hwnd
, LVM_GETHEADER
, 0, 0);
2309 ok(IsWindow(header
), "header expected\n");
2311 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2312 ok(style
& HDS_BUTTONS
, "expected header to have HDS_BUTTONS\n");
2314 style
= GetWindowLongPtr(hwnd
, GWL_STYLE
);
2315 SetWindowLongPtr(hwnd
, GWL_STYLE
, style
| LVS_NOSORTHEADER
);
2316 /* HDS_BUTTONS retained */
2317 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2318 ok(style
& HDS_BUTTONS
, "expected header to retain HDS_BUTTONS\n");
2320 DestroyWindow(hwnd
);
2322 /* create with LVS_NOSORTHEADER */
2323 hwnd
= create_listview_control(LVS_NOSORTHEADER
);
2324 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2326 header
= (HWND
)SendMessageA(hwnd
, LVM_GETHEADER
, 0, 0);
2327 ok(IsWindow(header
), "header expected\n");
2329 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2330 ok(!(style
& HDS_BUTTONS
), "expected header to have no HDS_BUTTONS\n");
2332 style
= GetWindowLongPtr(hwnd
, GWL_STYLE
);
2333 SetWindowLongPtr(hwnd
, GWL_STYLE
, style
& ~LVS_NOSORTHEADER
);
2334 /* not changed here */
2335 style
= GetWindowLongPtr(header
, GWL_STYLE
);
2336 ok(!(style
& HDS_BUTTONS
), "expected header to have no HDS_BUTTONS\n");
2338 DestroyWindow(hwnd
);
2341 static void test_setredraw(void)
2347 hwnd
= create_listview_control(0);
2348 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2350 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
2351 ListView seems to handle it internally without DefWinProc */
2353 /* default value first */
2354 ret
= SendMessage(hwnd
, WM_SETREDRAW
, TRUE
, 0);
2357 style
= GetWindowLongPtr(hwnd
, GWL_STYLE
);
2358 ok(style
& WS_VISIBLE
, "Expected WS_VISIBLE to be set\n");
2359 ret
= SendMessage(hwnd
, WM_SETREDRAW
, FALSE
, 0);
2361 style
= GetWindowLongPtr(hwnd
, GWL_STYLE
);
2362 ok(style
& WS_VISIBLE
, "Expected WS_VISIBLE to be set\n");
2364 DestroyWindow(hwnd
);
2367 static void test_hittest(void)
2373 static CHAR text
[] = "1234567890ABCDEFGHIJKLMNOPQRST";
2376 HIMAGELIST himl
, himl2
;
2379 hwnd
= create_listview_control(0);
2380 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2382 /* LVS_REPORT with a single subitem (2 columns) */
2383 insert_column(hwnd
, 0);
2384 insert_column(hwnd
, 1);
2385 insert_item(hwnd
, 0);
2388 /* the only purpose of that line is to be as long as a half item rect */
2389 item
.pszText
= text
;
2390 r
= SendMessage(hwnd
, LVM_SETITEMTEXT
, 0, (LPARAM
)&item
);
2393 r
= SendMessage(hwnd
, LVM_SETCOLUMNWIDTH
, 0, MAKELPARAM(100, 0));
2395 r
= SendMessage(hwnd
, LVM_SETCOLUMNWIDTH
, 1, MAKELPARAM(100, 0));
2398 memset(&bounds
, 0, sizeof(bounds
));
2399 bounds
.left
= LVIR_BOUNDS
;
2400 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
)&bounds
);
2401 ok(bounds
.bottom
- bounds
.top
> 0, "Expected non zero item height\n");
2402 ok(bounds
.right
- bounds
.left
> 0, "Expected non zero item width\n");
2403 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
)&pos
);
2406 /* LVS_EX_FULLROWSELECT not set, no icons attached */
2407 x
= pos
.x
+ 50; /* column half width */
2408 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2409 test_lvm_hittest(hwnd
, x
, y
, 0, LVHT_ONITEMLABEL
, FALSE
, FALSE
, __LINE__
);
2410 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 0, LVHT_ONITEMLABEL
, FALSE
, FALSE
, FALSE
, __LINE__
);
2411 x
= pos
.x
+ 150; /* outside column */
2412 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2413 test_lvm_hittest(hwnd
, x
, y
, -1, LVHT_TORIGHT
, FALSE
, FALSE
, __LINE__
);
2414 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 1, LVHT_ONITEMLABEL
, TRUE
, TRUE
, TRUE
, __LINE__
);
2415 /* parent client area is 100x100 by default */
2416 MoveWindow(hwnd
, 0, 0, 300, 100, FALSE
);
2417 x
= pos
.x
+ 150; /* outside column */
2418 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2419 test_lvm_hittest(hwnd
, x
, y
, -1, LVHT_NOWHERE
, FALSE
, FALSE
, __LINE__
);
2420 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 1, LVHT_ONITEMLABEL
, FALSE
, FALSE
, FALSE
, __LINE__
);
2421 /* the same with LVS_EX_FULLROWSELECT */
2422 SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
2423 x
= pos
.x
+ 150; /* outside column */
2424 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2425 test_lvm_hittest(hwnd
, x
, y
, 0, LVHT_ONITEM
, FALSE
, FALSE
, __LINE__
);
2426 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 1, LVHT_ONITEMLABEL
, FALSE
, FALSE
, FALSE
, __LINE__
);
2427 MoveWindow(hwnd
, 0, 0, 100, 100, FALSE
);
2428 x
= pos
.x
+ 150; /* outside column */
2429 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2430 test_lvm_hittest(hwnd
, x
, y
, -1, LVHT_TORIGHT
, FALSE
, FALSE
, __LINE__
);
2431 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 1, LVHT_ONITEMLABEL
, TRUE
, TRUE
, TRUE
, __LINE__
);
2432 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
2433 himl
= ImageList_Create(16, 16, 0, 4, 4);
2434 ok(himl
!= NULL
, "failed to create imagelist\n");
2435 hbmp
= CreateBitmap(16, 16, 1, 1, NULL
);
2436 ok(hbmp
!= NULL
, "failed to create bitmap\n");
2437 r
= ImageList_Add(himl
, hbmp
, 0);
2438 ok(r
== 0, "should be zero\n");
2439 hbmp
= CreateBitmap(16, 16, 1, 1, NULL
);
2440 ok(hbmp
!= NULL
, "failed to create bitmap\n");
2441 r
= ImageList_Add(himl
, hbmp
, 0);
2442 ok(r
== 1, "should be one\n");
2444 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)himl
);
2445 ok(r
== 0, "should return zero\n");
2447 item
.mask
= LVIF_IMAGE
;
2451 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
2455 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2456 test_lvm_hittest(hwnd
, x
, y
, 0, LVHT_ONITEMSTATEICON
, FALSE
, FALSE
, __LINE__
);
2457 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 0, LVHT_ONITEMSTATEICON
, FALSE
, FALSE
, FALSE
, __LINE__
);
2459 /* state icons indices are 1 based, check with valid index */
2460 item
.mask
= LVIF_STATE
;
2461 item
.state
= INDEXTOSTATEIMAGEMASK(1);
2462 item
.stateMask
= LVIS_STATEIMAGEMASK
;
2465 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
2469 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2470 test_lvm_hittest(hwnd
, x
, y
, 0, LVHT_ONITEMSTATEICON
, FALSE
, FALSE
, __LINE__
);
2471 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 0, LVHT_ONITEMSTATEICON
, FALSE
, FALSE
, FALSE
, __LINE__
);
2473 himl2
= (HIMAGELIST
)SendMessage(hwnd
, LVM_SETIMAGELIST
, LVSIL_STATE
, (LPARAM
)NULL
);
2474 ok(himl2
== himl
, "should return handle\n");
2476 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, LVSIL_SMALL
, (LPARAM
)himl
);
2477 ok(r
== 0, "should return zero\n");
2480 y
= pos
.y
+ (bounds
.bottom
- bounds
.top
) / 2;
2481 test_lvm_hittest(hwnd
, x
, y
, 0, LVHT_ONITEMICON
, FALSE
, FALSE
, __LINE__
);
2482 test_lvm_subitemhittest(hwnd
, x
, y
, 0, 0, LVHT_ONITEMICON
, FALSE
, FALSE
, FALSE
, __LINE__
);
2484 DestroyWindow(hwnd
);
2487 static void test_getviewrect(void)
2494 hwnd
= create_listview_control(0);
2495 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2498 r
= SendMessage(hwnd
, LVM_GETVIEWRECT
, 0, (LPARAM
)&rect
);
2501 insert_column(hwnd
, 0);
2502 insert_column(hwnd
, 1);
2504 memset(&item
, 0, sizeof(item
));
2507 SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
)&item
);
2509 r
= SendMessage(hwnd
, LVM_SETCOLUMNWIDTH
, 0, MAKELPARAM(100, 0));
2511 r
= SendMessage(hwnd
, LVM_SETCOLUMNWIDTH
, 1, MAKELPARAM(120, 0));
2514 rect
.left
= rect
.right
= rect
.top
= rect
.bottom
= -1;
2515 r
= SendMessage(hwnd
, LVM_GETVIEWRECT
, 0, (LPARAM
)&rect
);
2517 /* left is set to (2e31-1) - XP SP2 */
2518 expect(0, rect
.right
);
2519 expect(0, rect
.top
);
2520 expect(0, rect
.bottom
);
2522 /* switch to LVS_ICON */
2523 SetWindowLong(hwnd
, GWL_STYLE
, GetWindowLong(hwnd
, GWL_STYLE
) & ~LVS_REPORT
);
2525 rect
.left
= rect
.right
= rect
.top
= rect
.bottom
= -1;
2526 r
= SendMessage(hwnd
, LVM_GETVIEWRECT
, 0, (LPARAM
)&rect
);
2528 expect(0, rect
.left
);
2529 expect(0, rect
.top
);
2530 /* precise value differs for 2k, XP and Vista */
2531 ok(rect
.bottom
> 0, "Expected positive bottom value, got %d\n", rect
.bottom
);
2532 ok(rect
.right
> 0, "Expected positive right value, got %d\n", rect
.right
);
2534 DestroyWindow(hwnd
);
2537 static void test_getitemposition(void)
2544 hwnd
= create_listview_control(0);
2545 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2546 header
= subclass_header(hwnd
);
2548 /* LVS_REPORT, single item, no columns added */
2549 insert_item(hwnd
, 0);
2551 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2554 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
)&pt
);
2556 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, getitemposition_seq1
, "get item position 1", FALSE
);
2558 /* LVS_REPORT, single item, single column */
2559 insert_column(hwnd
, 0);
2561 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2564 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
)&pt
);
2566 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, getitemposition_seq2
, "get item position 2", TRUE
);
2568 memset(&rect
, 0, sizeof(rect
));
2569 SendMessage(header
, HDM_GETITEMRECT
, 0, (LPARAM
)&rect
);
2572 /* offset by header height */
2573 expect(rect
.bottom
- rect
.top
, pt
.y
);
2575 DestroyWindow(hwnd
);
2578 static void test_columnscreation(void)
2583 hwnd
= create_listview_control(0);
2584 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2586 insert_item(hwnd
, 0);
2588 /* headers columns aren't created automatically */
2589 header
= (HWND
)SendMessage(hwnd
, LVM_GETHEADER
, 0, 0);
2590 ok(IsWindow(header
), "Expected header handle\n");
2591 r
= SendMessage(header
, HDM_GETITEMCOUNT
, 0, 0);
2594 DestroyWindow(hwnd
);
2597 static void test_getitemrect(void)
2607 hwnd
= create_listview_control(0);
2608 ok(hwnd
!= NULL
, "failed to create a listview window\n");
2611 memset(&item
, 0, sizeof(item
));
2614 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
)&item
);
2617 rect
.left
= LVIR_BOUNDS
;
2618 rect
.right
= rect
.top
= rect
.bottom
= -1;
2619 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
)&rect
);
2622 /* zero width rectangle with no padding */
2623 expect(0, rect
.left
);
2624 todo_wine
expect(0, rect
.right
);
2626 insert_column(hwnd
, 0);
2627 insert_column(hwnd
, 1);
2629 col
.mask
= LVCF_WIDTH
;
2631 r
= SendMessage(hwnd
, LVM_SETCOLUMN
, 0, (LPARAM
)&col
);
2634 col
.mask
= LVCF_WIDTH
;
2636 r
= SendMessage(hwnd
, LVM_SETCOLUMN
, 1, (LPARAM
)&col
);
2639 rect
.left
= LVIR_BOUNDS
;
2640 rect
.right
= rect
.top
= rect
.bottom
= -1;
2641 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
)&rect
);
2644 /* still no left padding */
2645 expect(0, rect
.left
);
2646 expect(150, rect
.right
);
2648 rect
.left
= LVIR_SELECTBOUNDS
;
2649 rect
.right
= rect
.top
= rect
.bottom
= -1;
2650 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
)&rect
);
2653 todo_wine
expect(2, rect
.left
);
2656 order
[0] = 1; order
[1] = 0;
2657 r
= SendMessage(hwnd
, LVM_SETCOLUMNORDERARRAY
, 2, (LPARAM
)&order
);
2660 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
)&pt
);
2662 /* 1 indexed column width + padding */
2663 todo_wine
expect(102, pt
.x
);
2664 /* rect is at zero too */
2665 rect
.left
= LVIR_BOUNDS
;
2666 rect
.right
= rect
.top
= rect
.bottom
= -1;
2667 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
)&rect
);
2669 expect(0, rect
.left
);
2670 /* just width sum */
2671 expect(150, rect
.right
);
2673 rect
.left
= LVIR_SELECTBOUNDS
;
2674 rect
.right
= rect
.top
= rect
.bottom
= -1;
2675 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
)&rect
);
2677 /* column width + padding */
2678 todo_wine
expect(102, rect
.left
);
2680 DestroyWindow(hwnd
);
2683 START_TEST(listview
)
2686 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
2688 hComctl32
= GetModuleHandleA("comctl32.dll");
2689 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
2690 if (pInitCommonControlsEx
)
2692 INITCOMMONCONTROLSEX iccex
;
2693 iccex
.dwSize
= sizeof(iccex
);
2694 iccex
.dwICC
= ICC_LISTVIEW_CLASSES
;
2695 pInitCommonControlsEx(&iccex
);
2698 InitCommonControls();
2700 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
2702 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2703 hwndparent
= create_parent_window();
2704 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent window", TRUE
);
2705 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
2713 test_icon_spacing();
2716 test_item_position();
2721 test_subitem_rect();
2725 test_nosortheader();
2729 test_getitemposition();
2730 test_columnscreation();
2732 DestroyWindow(hwndparent
);