4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/test.h"
29 #define PARENT_SEQ_INDEX 0
30 #define LISTVIEW_SEQ_INDEX 1
31 #define NUM_MSG_SEQUENCES 2
36 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
37 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
38 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
42 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
44 static const struct message create_parent_wnd_seq
[] = {
45 { WM_GETMINMAXINFO
, sent
},
46 { WM_NCCREATE
, sent
},
47 { WM_NCCALCSIZE
, sent
|wparam
, 0 },
49 { WM_SHOWWINDOW
, sent
|wparam
, 1 },
50 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
51 { WM_QUERYNEWPALETTE
, sent
|optional
},
52 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
53 { WM_WINDOWPOSCHANGED
, sent
|optional
},
54 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
55 { WM_ACTIVATEAPP
, sent
|wparam
, 1 },
56 { WM_NCACTIVATE
, sent
|wparam
, 1 },
57 { WM_ACTIVATE
, sent
|wparam
, 1 },
58 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
59 { WM_IME_NOTIFY
, sent
|defwinproc
|optional
},
60 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
61 /* Win9x adds SWP_NOZORDER below */
62 { WM_WINDOWPOSCHANGED
, sent
, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
63 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
69 static const struct message redraw_listview_seq
[] = {
70 { WM_PAINT
, sent
|id
, 0, 0, LISTVIEW_ID
},
71 { WM_PAINT
, sent
|id
, 0, 0, HEADER_ID
},
72 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
73 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
74 { WM_NOTIFY
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
75 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
76 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
80 static const struct message listview_icon_spacing_seq
[] = {
81 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(20, 30) },
82 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(25, 35) },
83 { LVM_SETICONSPACING
, sent
|lparam
, 0, MAKELPARAM(-1, -1) },
87 static const struct message listview_color_seq
[] = {
88 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
89 { LVM_GETBKCOLOR
, sent
},
90 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
91 { LVM_GETTEXTCOLOR
, sent
},
92 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
93 { LVM_GETTEXTBKCOLOR
, sent
},
95 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
96 { LVM_GETBKCOLOR
, sent
},
97 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
98 { LVM_GETTEXTCOLOR
, sent
},
99 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
100 { LVM_GETTEXTBKCOLOR
, sent
},
102 { LVM_SETBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
103 { LVM_GETBKCOLOR
, sent
},
104 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, CLR_NONE
},
105 { LVM_GETTEXTCOLOR
, sent
},
106 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
107 { LVM_GETTEXTBKCOLOR
, sent
},
109 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
110 { LVM_GETBKCOLOR
, sent
},
111 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
112 { LVM_GETTEXTCOLOR
, sent
},
113 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
114 { LVM_GETTEXTBKCOLOR
, sent
},
118 static const struct message listview_item_count_seq
[] = {
119 { LVM_GETITEMCOUNT
, sent
},
120 { LVM_INSERTITEM
, sent
},
121 { LVM_INSERTITEM
, sent
},
122 { LVM_INSERTITEM
, sent
},
123 { LVM_GETITEMCOUNT
, sent
},
124 { LVM_DELETEITEM
, sent
|wparam
, 2 },
125 { LVM_GETITEMCOUNT
, sent
},
126 { LVM_DELETEALLITEMS
, sent
},
127 { LVM_GETITEMCOUNT
, sent
},
128 { LVM_INSERTITEM
, sent
},
129 { LVM_INSERTITEM
, sent
},
130 { LVM_GETITEMCOUNT
, sent
},
131 { LVM_INSERTITEM
, sent
},
132 { LVM_GETITEMCOUNT
, sent
},
136 static const struct message listview_itempos_seq
[] = {
137 { LVM_INSERTITEM
, sent
},
138 { LVM_INSERTITEM
, sent
},
139 { LVM_INSERTITEM
, sent
},
140 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 1, MAKELPARAM(10,5) },
141 { LVM_GETITEMPOSITION
, sent
|wparam
, 1 },
142 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 2, MAKELPARAM(0,0) },
143 { LVM_GETITEMPOSITION
, sent
|wparam
, 2 },
144 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 0, MAKELPARAM(20,20) },
145 { LVM_GETITEMPOSITION
, sent
|wparam
, 0 },
149 static const struct message listview_ownerdata_switchto_seq
[] = {
150 { WM_STYLECHANGING
, sent
},
151 { WM_STYLECHANGED
, sent
},
155 static const struct message listview_getorderarray_seq
[] = {
156 { LVM_GETCOLUMNORDERARRAY
, sent
|id
|wparam
, 2, 0, LISTVIEW_ID
},
157 { HDM_GETORDERARRAY
, sent
|id
|wparam
, 2, 0, HEADER_ID
},
161 static const struct message empty_seq
[] = {
170 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
172 static LONG defwndproc_counter
= 0;
176 /* log system messages, except for painting */
177 if (message
< WM_USER
&&
178 message
!= WM_PAINT
&&
179 message
!= WM_ERASEBKGND
&&
180 message
!= WM_NCPAINT
&&
181 message
!= WM_NCHITTEST
&&
182 message
!= WM_GETTEXT
&&
183 message
!= WM_GETICON
&&
184 message
!= WM_DEVICECHANGE
)
186 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
188 msg
.message
= message
;
189 msg
.flags
= sent
|wparam
|lparam
;
190 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
193 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
196 defwndproc_counter
++;
197 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
198 defwndproc_counter
--;
203 static BOOL
register_parent_wnd_class(void)
208 cls
.lpfnWndProc
= parent_wnd_proc
;
211 cls
.hInstance
= GetModuleHandleA(NULL
);
213 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
214 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
215 cls
.lpszMenuName
= NULL
;
216 cls
.lpszClassName
= "Listview test parent class";
217 return RegisterClassA(&cls
);
220 static HWND
create_parent_window(void)
222 if (!register_parent_wnd_class())
225 return CreateWindowEx(0, "Listview test parent class",
226 "Listview test parent window",
227 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
228 WS_MAXIMIZEBOX
| WS_VISIBLE
,
230 GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
233 static LRESULT WINAPI
listview_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
235 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
236 static LONG defwndproc_counter
= 0;
240 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
242 /* some debug output for style changing */
243 if ((message
== WM_STYLECHANGING
||
244 message
== WM_STYLECHANGED
) && lParam
)
246 STYLESTRUCT
*style
= (STYLESTRUCT
*)lParam
;
247 trace("\told style: 0x%08x, new style: 0x%08x\n", style
->styleOld
, style
->styleNew
);
250 msg
.message
= message
;
251 msg
.flags
= sent
|wparam
|lparam
;
252 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
255 msg
.id
= LISTVIEW_ID
;
256 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
258 defwndproc_counter
++;
259 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
260 defwndproc_counter
--;
264 static HWND
create_listview_control(DWORD style
)
266 struct subclass_info
*info
;
270 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
274 GetClientRect(hwndparent
, &rect
);
275 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
276 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| LVS_REPORT
| style
,
277 0, 0, rect
.right
, rect
.bottom
,
278 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
279 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
283 HeapFree(GetProcessHeap(), 0, info
);
287 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
288 (LONG_PTR
)listview_subclass_proc
);
289 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
294 static HWND
create_custom_listview_control(DWORD style
)
296 struct subclass_info
*info
;
300 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
304 GetClientRect(hwndparent
, &rect
);
305 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
306 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
307 0, 0, rect
.right
, rect
.bottom
,
308 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
309 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
313 HeapFree(GetProcessHeap(), 0, info
);
317 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
318 (LONG_PTR
)listview_subclass_proc
);
319 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
324 static LRESULT WINAPI
header_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
326 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
327 static LONG defwndproc_counter
= 0;
331 trace("header: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
333 msg
.message
= message
;
334 msg
.flags
= sent
|wparam
|lparam
;
335 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
339 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
341 defwndproc_counter
++;
342 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
343 defwndproc_counter
--;
347 static HWND
subclass_header(HWND hwndListview
)
349 struct subclass_info
*info
;
352 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
356 hwnd
= ListView_GetHeader(hwndListview
);
357 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
358 (LONG_PTR
)header_subclass_proc
);
359 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
364 static void test_images(void)
372 static CHAR hello
[] = "hello";
374 himl
= ImageList_Create(40, 40, 0, 4, 4);
375 ok(himl
!= NULL
, "failed to create imagelist\n");
377 hbmp
= CreateBitmap(40, 40, 1, 1, NULL
);
378 ok(hbmp
!= NULL
, "failed to create bitmap\n");
380 r
= ImageList_Add(himl
, hbmp
, 0);
381 ok(r
== 0, "should be zero\n");
383 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED
,
384 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
385 ok(hwnd
!= NULL
, "failed to create listview window\n");
387 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, 0x940);
388 ok(r
== 0, "should return zero\n");
390 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)himl
);
391 ok(r
== 0, "should return zero\n");
393 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELONG(100,50));
394 /* returns dimensions */
396 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
397 ok(r
== 0, "should be zero items\n");
399 item
.mask
= LVIF_IMAGE
| LVIF_TEXT
;
404 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
405 ok(r
== -1, "should fail\n");
408 item
.pszText
= hello
;
409 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
410 ok(r
== 0, "should not fail\n");
412 memset(&r1
, 0, sizeof r1
);
414 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r1
);
416 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
417 ok(r
== TRUE
, "should not fail\n");
420 item
.pszText
= hello
;
421 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
422 ok(r
== 0, "should not fail\n");
424 memset(&r2
, 0, sizeof r2
);
426 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r2
);
428 ok(!memcmp(&r1
, &r2
, sizeof r1
), "rectangle should be the same\n");
433 static void test_checkboxes(void)
438 static CHAR text
[] = "Text",
442 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
443 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
444 ok(hwnd
!= NULL
, "failed to create listview window\n");
446 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
447 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
448 item
.stateMask
= 0xffff;
453 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
454 ok(r
== 0, "ret %d\n", r
);
457 item
.mask
= LVIF_STATE
;
458 item
.stateMask
= 0xffff;
459 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
460 ok(item
.state
== 0xfccc, "state %x\n", item
.state
);
462 /* Don't set LVIF_STATE */
463 item
.mask
= LVIF_TEXT
;
464 item
.stateMask
= 0xffff;
469 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
470 ok(r
== 1, "ret %d\n", r
);
473 item
.mask
= LVIF_STATE
;
474 item
.stateMask
= 0xffff;
475 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
476 ok(item
.state
== 0, "state %x\n", item
.state
);
478 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
479 ok(r
== 0, "should return zero\n");
481 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
483 item
.mask
= LVIF_STATE
;
484 item
.stateMask
= 0xffff;
485 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
486 ok(item
.state
== 0x1ccc, "state %x\n", item
.state
);
488 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
490 item
.mask
= LVIF_TEXT
;
492 item
.pszText
= text2
;
493 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
494 ok(r
== 2, "ret %d\n", r
);
497 item
.mask
= LVIF_STATE
;
498 item
.stateMask
= 0xffff;
499 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
500 ok(item
.state
== 0x1000, "state %x\n", item
.state
);
502 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
504 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
505 item
.stateMask
= 0xffff;
507 item
.pszText
= text3
;
508 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
509 ok(r
== 3, "ret %d\n", r
);
512 item
.mask
= LVIF_STATE
;
513 item
.stateMask
= 0xffff;
514 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
515 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
517 /* Set an item's state to checked */
519 item
.mask
= LVIF_STATE
;
520 item
.stateMask
= 0xf000;
522 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
525 item
.mask
= LVIF_STATE
;
526 item
.stateMask
= 0xffff;
527 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
528 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
530 /* Check that only the bits we asked for are returned,
531 * and that all the others are set to zero
534 item
.mask
= LVIF_STATE
;
535 item
.stateMask
= 0xf000;
537 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
538 ok(item
.state
== 0x2000, "state %x\n", item
.state
);
540 /* Set the style again and check that doesn't change an item's state */
541 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
542 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
545 item
.mask
= LVIF_STATE
;
546 item
.stateMask
= 0xffff;
547 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
548 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
550 /* Unsetting the checkbox extended style doesn't change an item's state */
551 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, 0);
552 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
555 item
.mask
= LVIF_STATE
;
556 item
.stateMask
= 0xffff;
557 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
558 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
560 /* Now setting the style again will change an item's state */
561 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
562 ok(r
== 0, "ret %x\n", r
);
565 item
.mask
= LVIF_STATE
;
566 item
.stateMask
= 0xffff;
567 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
568 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
570 /* Toggle checkbox tests (bug 9934) */
571 memset (&item
, 0xcc, sizeof(item
));
572 item
.mask
= LVIF_STATE
;
575 item
.state
= LVIS_FOCUSED
;
576 item
.stateMask
= LVIS_FOCUSED
;
577 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
581 item
.mask
= LVIF_STATE
;
582 item
.stateMask
= 0xffff;
583 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
584 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
586 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
588 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
592 item
.mask
= LVIF_STATE
;
593 item
.stateMask
= 0xffff;
594 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
595 ok(item
.state
== 0x2aab, "state %x\n", item
.state
);
597 r
= SendMessage(hwnd
, WM_KEYDOWN
, VK_SPACE
, 0);
599 r
= SendMessage(hwnd
, WM_KEYUP
, VK_SPACE
, 0);
603 item
.mask
= LVIF_STATE
;
604 item
.stateMask
= 0xffff;
605 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
606 ok(item
.state
== 0x1aab, "state %x\n", item
.state
);
611 static void insert_column(HWND hwnd
, int idx
)
616 memset(&column
, 0xcc, sizeof(column
));
617 column
.mask
= LVCF_SUBITEM
;
618 column
.iSubItem
= idx
;
620 rc
= ListView_InsertColumn(hwnd
, idx
, &column
);
624 static void insert_item(HWND hwnd
, int idx
)
626 static CHAR text
[] = "foo";
631 memset(&item
, 0xcc, sizeof (item
));
632 item
.mask
= LVIF_TEXT
;
637 rc
= ListView_InsertItem(hwnd
, &item
);
641 static void test_items(void)
643 const LPARAM lparamTest
= 0x42;
647 static CHAR text
[] = "Text";
649 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
650 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
651 ok(hwnd
!= NULL
, "failed to create listview window\n");
654 * Test setting/getting item params
657 /* Set up two columns */
658 insert_column(hwnd
, 0);
659 insert_column(hwnd
, 1);
661 /* LVIS_SELECTED with zero stateMask */
663 memset (&item
, 0, sizeof (item
));
664 item
.mask
= LVIF_STATE
;
665 item
.state
= LVIS_SELECTED
;
669 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
670 ok(r
== 0, "ret %d\n", r
);
672 memset (&item
, 0xcc, sizeof (item
));
673 item
.mask
= LVIF_STATE
;
674 item
.stateMask
= LVIS_SELECTED
;
678 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
679 ok(r
!= 0, "ret %d\n", r
);
680 ok(item
.state
& LVIS_SELECTED
, "Expected LVIS_SELECTED\n");
681 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
683 /* LVIS_SELECTED with zero stateMask */
685 memset (&item
, 0, sizeof (item
));
686 item
.mask
= LVIF_STATE
;
687 item
.state
= LVIS_FOCUSED
;
691 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
692 ok(r
== 0, "ret %d\n", r
);
694 memset (&item
, 0xcc, sizeof (item
));
695 item
.mask
= LVIF_STATE
;
696 item
.stateMask
= LVIS_FOCUSED
;
700 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
701 ok(r
!= 0, "ret %d\n", r
);
702 ok(item
.state
& LVIS_FOCUSED
, "Expected LVIS_FOCUSED\n");
703 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
705 /* LVIS_CUT with LVIS_FOCUSED stateMask */
707 memset (&item
, 0, sizeof (item
));
708 item
.mask
= LVIF_STATE
;
709 item
.state
= LVIS_CUT
;
710 item
.stateMask
= LVIS_FOCUSED
;
713 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
714 ok(r
== 0, "ret %d\n", r
);
716 memset (&item
, 0xcc, sizeof (item
));
717 item
.mask
= LVIF_STATE
;
718 item
.stateMask
= LVIS_CUT
;
722 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
723 ok(r
!= 0, "ret %d\n", r
);
724 ok(item
.state
& LVIS_CUT
, "Expected LVIS_CUT\n");
725 SendMessage(hwnd
, LVM_DELETEITEM
, 0, 0);
727 /* Insert an item with just a param */
728 memset (&item
, 0xcc, sizeof (item
));
729 item
.mask
= LVIF_PARAM
;
732 item
.lParam
= lparamTest
;
733 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
734 ok(r
== 0, "ret %d\n", r
);
736 /* Test getting of the param */
737 memset (&item
, 0xcc, sizeof (item
));
738 item
.mask
= LVIF_PARAM
;
741 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
742 ok(r
!= 0, "ret %d\n", r
);
743 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
745 /* Set up a subitem */
746 memset (&item
, 0xcc, sizeof (item
));
747 item
.mask
= LVIF_TEXT
;
751 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
752 ok(r
!= 0, "ret %d\n", r
);
754 /* Query param from subitem: returns main item param */
755 memset (&item
, 0xcc, sizeof (item
));
756 item
.mask
= LVIF_PARAM
;
759 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
760 ok(r
!= 0, "ret %d\n", r
);
761 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
763 /* Set up param on first subitem: no effect */
764 memset (&item
, 0xcc, sizeof (item
));
765 item
.mask
= LVIF_PARAM
;
768 item
.lParam
= lparamTest
+1;
769 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
770 ok(r
== 0, "ret %d\n", r
);
772 /* Query param from subitem again: should still return main item param */
773 memset (&item
, 0xcc, sizeof (item
));
774 item
.mask
= LVIF_PARAM
;
777 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
778 ok(r
!= 0, "ret %d\n", r
);
779 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
781 /**** Some tests of state highlighting ****/
782 memset (&item
, 0xcc, sizeof (item
));
783 item
.mask
= LVIF_STATE
;
786 item
.state
= LVIS_SELECTED
;
787 item
.stateMask
= LVIS_SELECTED
| LVIS_DROPHILITED
;
788 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
789 ok(r
!= 0, "ret %d\n", r
);
791 item
.state
= LVIS_DROPHILITED
;
792 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
793 ok(r
!= 0, "ret %d\n", r
);
795 memset (&item
, 0xcc, sizeof (item
));
796 item
.mask
= LVIF_STATE
;
800 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
801 ok(r
!= 0, "ret %d\n", r
);
802 ok(item
.state
== LVIS_SELECTED
, "got state %x, expected %x\n", item
.state
, LVIS_SELECTED
);
804 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
805 ok(r
!= 0, "ret %d\n", r
);
806 todo_wine
ok(item
.state
== LVIS_DROPHILITED
, "got state %x, expected %x\n", item
.state
, LVIS_DROPHILITED
);
808 /* some notnull but meaningless masks */
809 memset (&item
, 0, sizeof(item
));
810 item
.mask
= LVIF_NORECOMPUTE
;
813 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
814 ok(r
!= 0, "ret %d\n", r
);
815 memset (&item
, 0, sizeof(item
));
816 item
.mask
= LVIF_DI_SETITEM
;
819 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
820 ok(r
!= 0, "ret %d\n", r
);
825 static void test_columns(void)
827 HWND hwnd
, hwndheader
;
832 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
833 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
834 ok(hwnd
!= NULL
, "failed to create listview window\n");
836 /* Add a column with no mask */
837 memset(&column
, 0xcc, sizeof(column
));
839 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
840 ok(rc
==0, "Inserting column with no mask failed with %d\n", rc
);
842 /* Check its width */
843 rc
= ListView_GetColumnWidth(hwnd
, 0);
845 broken(rc
==0), /* win9x */
846 "Inserting column with no mask failed to set width to 10 with %d\n", rc
);
850 /* LVM_GETCOLUMNORDERARRAY */
851 hwnd
= create_listview_control(0);
852 hwndheader
= subclass_header(hwnd
);
854 memset(&column
, 0, sizeof(column
));
855 column
.mask
= LVCF_WIDTH
;
857 rc
= ListView_InsertColumn(hwnd
, 0, &column
);
858 ok(rc
== 0, "Inserting column failed with %d\n", rc
);
861 rc
= ListView_InsertColumn(hwnd
, 1, &column
);
862 ok(rc
== 1, "Inserting column failed with %d\n", rc
);
864 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
866 rc
= SendMessage(hwnd
, LVM_GETCOLUMNORDERARRAY
, 2, (LPARAM
)&order
);
867 ok(rc
!= 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
868 ok(order
[0] == 0, "Expected order 0, got %d\n", order
[0]);
869 ok(order
[1] == 1, "Expected order 1, got %d\n", order
[1]);
871 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_getorderarray_seq
, "get order array", FALSE
);
875 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
876 static WNDPROC listviewWndProc
;
877 static HIMAGELIST test_create_imagelist
;
879 static LRESULT CALLBACK
create_test_wndproc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
883 if (uMsg
== WM_CREATE
)
885 LPCREATESTRUCT lpcs
= (LPCREATESTRUCT
)lParam
;
886 lpcs
->style
|= LVS_REPORT
;
888 ret
= CallWindowProc(listviewWndProc
, hwnd
, uMsg
, wParam
, lParam
);
889 if (uMsg
== WM_CREATE
) SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)test_create_imagelist
);
893 static void test_create(void)
902 cls
.cbSize
= sizeof(WNDCLASSEX
);
903 ok(GetClassInfoEx(GetModuleHandle(NULL
), "SysListView32", &cls
), "GetClassInfoEx failed\n");
904 listviewWndProc
= cls
.lpfnWndProc
;
905 cls
.lpfnWndProc
= create_test_wndproc
;
906 cls
.lpszClassName
= "MyListView32";
907 ok(RegisterClassEx(&cls
), "RegisterClassEx failed\n");
909 test_create_imagelist
= ImageList_Create(16, 16, 0, 5, 10);
910 hList
= CreateWindow("MyListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
911 ok((HIMAGELIST
)SendMessage(hList
, LVM_GETIMAGELIST
, 0, 0) == test_create_imagelist
, "Image list not obtained\n");
912 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
913 ok(IsWindow(hHeader
) && IsWindowVisible(hHeader
), "Listview not in report mode\n");
914 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
915 DestroyWindow(hList
);
917 /* header isn't created on LVS_ICON and LVS_LIST styles */
918 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
919 GetModuleHandle(NULL
), 0);
920 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
921 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
922 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
924 memset(&col
, 0, sizeof(LVCOLUMNA
));
925 col
.mask
= LVCF_WIDTH
;
927 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
928 ok(r
== 0, "Expected 0 column's inserted\n");
929 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
930 ok(IsWindow(hHeader
), "Header should be created\n");
931 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
932 DestroyWindow(hList
);
934 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
935 GetModuleHandle(NULL
), 0);
936 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
937 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
938 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
940 memset(&col
, 0, sizeof(LVCOLUMNA
));
941 col
.mask
= LVCF_WIDTH
;
943 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
944 ok(r
== 0, "Expected 0 column's inserted\n");
945 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
946 ok(IsWindow(hHeader
), "Header should be created\n");
947 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
948 DestroyWindow(hList
);
950 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
951 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
,
952 GetModuleHandle(NULL
), 0);
953 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLongPtr(hList
, GWL_STYLE
) | LVS_REPORT
);
954 ok(ret
& WS_VISIBLE
, "Style wrong, should have WS_VISIBLE\n");
955 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
956 ok(IsWindow(hHeader
), "Header should be created\n");
957 ret
= SetWindowLongPtr(hList
, GWL_STYLE
, GetWindowLong(hList
, GWL_STYLE
) & ~LVS_REPORT
);
958 ok((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
959 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
960 ok(IsWindow(hHeader
), "Header should be created\n");
961 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
962 DestroyWindow(hList
);
964 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
965 hList
= CreateWindow("SysListView32", "Test", WS_VISIBLE
|LVS_LIST
, 0, 0, 100, 100, NULL
, NULL
,
966 GetModuleHandle(NULL
), 0);
967 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
968 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_LIST
) | LVS_REPORT
);
969 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_LIST
)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
970 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
971 ok(IsWindow(hHeader
), "Header should be created\n");
972 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
973 ret
= SetWindowLongPtr(hList
, GWL_STYLE
,
974 (GetWindowLongPtr(hList
, GWL_STYLE
) & ~LVS_REPORT
) | LVS_LIST
);
975 ok(((ret
& WS_VISIBLE
) && (ret
& LVS_REPORT
)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
976 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
977 ok(IsWindow(hHeader
), "Header should be created\n");
978 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
979 DestroyWindow(hList
);
981 /* LVS_REPORT without WS_VISIBLE */
982 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
983 GetModuleHandle(NULL
), 0);
984 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
985 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
986 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
988 memset(&col
, 0, sizeof(LVCOLUMNA
));
989 col
.mask
= LVCF_WIDTH
;
991 r
= SendMessage(hList
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
992 ok(r
== 0, "Expected 0 column's inserted\n");
993 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
994 ok(IsWindow(hHeader
), "Header should be created\n");
995 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
996 DestroyWindow(hList
);
998 /* LVS_REPORT without WS_VISIBLE, try to show it */
999 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1000 GetModuleHandle(NULL
), 0);
1001 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1002 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1003 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1004 ShowWindow(hList
, SW_SHOW
);
1005 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1006 ok(IsWindow(hHeader
), "Header should be created\n");
1007 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1008 DestroyWindow(hList
);
1010 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1011 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
|LVS_NOCOLUMNHEADER
|WS_VISIBLE
,
1012 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
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 /* HDS_DRAGDROP set by default */
1017 ok(GetWindowLongPtr(hHeader
, GWL_STYLE
) & HDS_DRAGDROP
, "Expected header to have HDS_DRAGDROP\n");
1018 DestroyWindow(hList
);
1020 /* setting LVS_EX_HEADERDRAGDROP creates header */
1021 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1022 GetModuleHandle(NULL
), 0);
1023 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1024 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1025 SendMessage(hList
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_HEADERDRAGDROP
);
1026 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1027 ok(IsWindow(hHeader
), "Header should be created\n");
1028 ok(hHeader
== GetDlgItem(hList
, 0), "Expected header as dialog item\n");
1029 DestroyWindow(hList
);
1031 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1032 hList
= CreateWindow("SysListView32", "Test", LVS_REPORT
, 0, 0, 100, 100, NULL
, NULL
,
1033 GetModuleHandle(NULL
), 0);
1034 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1035 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1037 rect
.left
= LVIR_BOUNDS
;
1039 rect
.right
= rect
.bottom
= -10;
1040 r
= SendMessage(hList
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1041 ok(r
!= 0, "Expected not-null LRESULT\n");
1043 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
1044 ok(!IsWindow(hHeader
), "Header shouldn't be created\n");
1045 ok(NULL
== GetDlgItem(hList
, 0), "NULL dialog item expected\n");
1047 DestroyWindow(hList
);
1050 static void test_redraw(void)
1052 HWND hwnd
, hwndheader
;
1054 hwnd
= create_listview_control(0);
1055 hwndheader
= subclass_header(hwnd
);
1057 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1059 trace("invalidate & update\n");
1060 InvalidateRect(hwnd
, NULL
, TRUE
);
1062 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, redraw_listview_seq
, "redraw listview", FALSE
);
1064 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1066 DestroyWindow(hwnd
);
1069 static LRESULT WINAPI
cd_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1071 COLORREF clr
, c0ffee
= RGB(0xc0, 0xff, 0xee);
1073 if(msg
== WM_NOTIFY
) {
1074 NMHDR
*nmhdr
= (PVOID
)lp
;
1075 if(nmhdr
->code
== NM_CUSTOMDRAW
) {
1076 NMLVCUSTOMDRAW
*nmlvcd
= (PVOID
)nmhdr
;
1077 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd
->nmcd
.dwDrawStage
);
1078 switch(nmlvcd
->nmcd
.dwDrawStage
) {
1080 SetBkColor(nmlvcd
->nmcd
.hdc
, c0ffee
);
1081 return CDRF_NOTIFYITEMDRAW
;
1082 case CDDS_ITEMPREPAINT
:
1083 nmlvcd
->clrTextBk
= CLR_DEFAULT
;
1084 return CDRF_NOTIFYSUBITEMDRAW
;
1085 case CDDS_ITEMPREPAINT
| CDDS_SUBITEM
:
1086 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1087 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1088 return CDRF_NOTIFYPOSTPAINT
;
1089 case CDDS_ITEMPOSTPAINT
| CDDS_SUBITEM
:
1090 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
1091 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
1092 return CDRF_DODEFAULT
;
1094 return CDRF_DODEFAULT
;
1098 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
1101 static void test_customdraw(void)
1106 hwnd
= create_listview_control(0);
1108 insert_column(hwnd
, 0);
1109 insert_column(hwnd
, 1);
1110 insert_item(hwnd
, 0);
1112 oldwndproc
= (WNDPROC
)SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
,
1113 (LONG_PTR
)cd_wndproc
);
1115 InvalidateRect(hwnd
, NULL
, TRUE
);
1118 SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
, (LONG_PTR
)oldwndproc
);
1120 DestroyWindow(hwnd
);
1123 static void test_icon_spacing(void)
1125 /* LVM_SETICONSPACING */
1126 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1132 hwnd
= create_custom_listview_control(LVS_ICON
);
1133 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1135 r
= SendMessage(hwnd
, WM_NOTIFYFORMAT
, (WPARAM
)hwndparent
, (LPARAM
)NF_REQUERY
);
1136 expect(NFR_ANSI
, r
);
1138 /* reset the icon spacing to defaults */
1139 SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1141 /* now we can request what the defaults are */
1142 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1, -1));
1146 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1148 trace("test icon spacing\n");
1150 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(20, 30));
1151 ok(r
== MAKELONG(w
, h
) ||
1152 broken(r
== MAKELONG(w
, w
)), /* win98 */
1153 "Expected %d, got %d\n", MAKELONG(w
, h
), r
);
1155 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(25, 35));
1156 expect(MAKELONG(20,30), r
);
1158 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELPARAM(-1,-1));
1159 expect(MAKELONG(25,35), r
);
1161 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_icon_spacing_seq
, "test icon spacing seq", FALSE
);
1163 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1164 DestroyWindow(hwnd
);
1167 static void test_color(void)
1169 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1176 COLORREF colors
[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE
, RGB(255,255,255)};
1178 hwnd
= create_listview_control(0);
1179 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1181 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1183 trace("test color seq\n");
1184 for (i
= 0; i
< 4; i
++)
1188 r
= SendMessage(hwnd
, LVM_SETBKCOLOR
, 0, color
);
1190 r
= SendMessage(hwnd
, LVM_GETBKCOLOR
, 0, color
);
1193 r
= SendMessage(hwnd
, LVM_SETTEXTCOLOR
, 0, color
);
1195 r
= SendMessage(hwnd
, LVM_GETTEXTCOLOR
, 0, color
);
1198 r
= SendMessage(hwnd
, LVM_SETTEXTBKCOLOR
, 0, color
);
1200 r
= SendMessage(hwnd
, LVM_GETTEXTBKCOLOR
, 0, color
);
1204 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_color_seq
, "test color seq", FALSE
);
1206 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1207 DestroyWindow(hwnd
);
1210 static void test_item_count(void)
1212 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1220 static CHAR item0text
[] = "item0";
1221 static CHAR item1text
[] = "item1";
1222 static CHAR item2text
[] = "item2";
1224 hwnd
= create_listview_control(0);
1225 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1227 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1229 trace("test item count\n");
1231 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1235 item0
.mask
= LVIF_TEXT
;
1238 item0
.pszText
= item0text
;
1239 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1242 /* [item0, item1] */
1243 item1
.mask
= LVIF_TEXT
;
1246 item1
.pszText
= item1text
;
1247 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1250 /* [item0, item1, item2] */
1251 item2
.mask
= LVIF_TEXT
;
1254 item2
.pszText
= item2text
;
1255 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1258 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1261 /* [item0, item1] */
1262 r
= SendMessage(hwnd
, LVM_DELETEITEM
, 2, 0);
1265 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1269 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
1272 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1276 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1279 /* [item0, item1] */
1280 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1283 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1286 /* [item0, item1, item2] */
1287 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1290 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1293 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_item_count_seq
, "test item count seq", FALSE
);
1295 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1296 DestroyWindow(hwnd
);
1299 static void test_item_position(void)
1301 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1310 static CHAR item0text
[] = "item0";
1311 static CHAR item1text
[] = "item1";
1312 static CHAR item2text
[] = "item2";
1314 hwnd
= create_custom_listview_control(LVS_ICON
);
1315 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1317 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1319 trace("test item position\n");
1322 item0
.mask
= LVIF_TEXT
;
1325 item0
.pszText
= item0text
;
1326 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
1329 /* [item0, item1] */
1330 item1
.mask
= LVIF_TEXT
;
1333 item1
.pszText
= item1text
;
1334 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
1337 /* [item0, item1, item2] */
1338 item2
.mask
= LVIF_TEXT
;
1341 item2
.pszText
= item2text
;
1342 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
1345 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 1, MAKELPARAM(10,5));
1347 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 1, (LPARAM
) &position
);
1349 expect2(10, 5, position
.x
, position
.y
);
1351 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 2, MAKELPARAM(0,0));
1353 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 2, (LPARAM
) &position
);
1355 expect2(0, 0, position
.x
, position
.y
);
1357 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 0, MAKELPARAM(20,20));
1359 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
) &position
);
1361 expect2(20, 20, position
.x
, position
.y
);
1363 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_itempos_seq
, "test item position seq", TRUE
);
1365 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1366 DestroyWindow(hwnd
);
1369 static void test_getorigin(void)
1377 position
.x
= position
.y
= 0;
1379 hwnd
= create_custom_listview_control(LVS_ICON
);
1380 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1381 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1382 trace("test get origin results\n");
1383 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1385 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1386 DestroyWindow(hwnd
);
1388 hwnd
= create_custom_listview_control(LVS_SMALLICON
);
1389 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1390 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1391 trace("test get origin results\n");
1392 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1394 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1395 DestroyWindow(hwnd
);
1397 hwnd
= create_custom_listview_control(LVS_LIST
);
1398 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1399 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1400 trace("test get origin results\n");
1401 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1403 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1404 DestroyWindow(hwnd
);
1406 hwnd
= create_custom_listview_control(LVS_REPORT
);
1407 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1408 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1409 trace("test get origin results\n");
1410 r
= SendMessage(hwnd
, LVM_GETORIGIN
, 0, (LPARAM
)&position
);
1412 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1413 DestroyWindow(hwnd
);
1417 static void test_multiselect(void)
1419 typedef struct t_select_task
1430 int i
,j
,item_count
,selected_count
;
1431 static const int items
=5;
1436 static struct t_select_task task_list
[] = {
1437 { "using VK_DOWN", 0, VK_DOWN
, -1, -1 },
1438 { "using VK_UP", -1, VK_UP
, -1, -1 },
1439 { "using VK_END", 0, VK_END
, 1, -1 },
1440 { "using VK_HOME", -1, VK_HOME
, 1, -1 }
1444 hwnd
= create_listview_control(0);
1446 for (i
=0;i
<items
;i
++) {
1447 insert_item(hwnd
, 0);
1450 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1452 expect(items
,item_count
);
1455 task
= task_list
[i
];
1457 /* deselect all items */
1458 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1459 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1461 /* set initial position */
1462 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, (task
.initPos
== -1 ? item_count
-1 : task
.initPos
));
1463 ListView_SetItemState(hwnd
,(task
.initPos
== -1 ? item_count
-1 : task
.initPos
),LVIS_SELECTED
,LVIS_SELECTED
);
1465 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1467 ok(selected_count
== 1, "There should be only one selected item at the beginning (is %d)\n",selected_count
);
1469 /* Set SHIFT key pressed */
1470 GetKeyboardState(kstate
);
1471 kstate
[VK_SHIFT
]=0x80;
1472 SetKeyboardState(kstate
);
1474 for (j
=1;j
<=(task
.count
== -1 ? item_count
: task
.count
);j
++) {
1475 r
= SendMessage(hwnd
, WM_KEYDOWN
, task
.loopVK
, 0);
1477 r
= SendMessage(hwnd
, WM_KEYUP
, task
.loopVK
, 0);
1481 selected_count
= (int)SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1483 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
);
1485 /* Set SHIFT key released */
1486 GetKeyboardState(kstate
);
1487 kstate
[VK_SHIFT
]=0x00;
1488 SetKeyboardState(kstate
);
1490 DestroyWindow(hwnd
);
1492 /* make multiple selection, then switch to LVS_SINGLESEL */
1493 hwnd
= create_listview_control(0);
1494 for (i
=0;i
<items
;i
++) {
1495 insert_item(hwnd
, 0);
1497 item_count
= (int)SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1498 expect(items
,item_count
);
1499 /* deselect all items */
1500 ListView_SetItemState(hwnd
, -1, 0, LVIS_SELECTED
);
1501 SendMessage(hwnd
, LVM_SETSELECTIONMARK
, 0, -1);
1503 ListView_SetItemState(hwnd
, i
, LVIS_SELECTED
, LVIS_SELECTED
);
1506 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1508 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1512 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1513 ok(!(style
& LVS_SINGLESEL
), "LVS_SINGLESEL isn't expected\n");
1514 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SINGLESEL
);
1515 /* check that style is accepted */
1516 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1517 ok(style
& LVS_SINGLESEL
, "LVS_SINGLESEL expected\n");
1520 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1521 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1523 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1525 SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1528 /* select one more */
1529 ListView_SetItemState(hwnd
, 3, LVIS_SELECTED
, LVIS_SELECTED
);
1532 r
= ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
);
1533 ok(!(r
& LVIS_SELECTED
), "Expected item %d to be unselected\n", i
);
1535 r
= ListView_GetItemState(hwnd
, 3, LVIS_SELECTED
);
1536 ok(r
& LVIS_SELECTED
, "Expected item %d to be selected\n", i
);
1538 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1540 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1544 DestroyWindow(hwnd
);
1547 static void test_subitem_rect(void)
1554 /* test LVM_GETSUBITEMRECT for header */
1555 hwnd
= create_listview_control(0);
1556 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1557 /* add some columns */
1558 memset(&col
, 0, sizeof(LVCOLUMN
));
1559 col
.mask
= LVCF_WIDTH
;
1562 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 0, (LPARAM
)&col
);
1566 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 1, (LPARAM
)&col
);
1570 r
= SendMessage(hwnd
, LVM_INSERTCOLUMN
, 2, (LPARAM
)&col
);
1572 /* item = -1 means header, subitem index is 1 based */
1573 rect
.left
= LVIR_BOUNDS
;
1575 rect
.right
= rect
.bottom
= 0;
1576 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1579 rect
.left
= LVIR_BOUNDS
;
1581 rect
.right
= rect
.bottom
= 0;
1582 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1584 ok(r
!= 0, "Expected not-null LRESULT\n");
1585 expect(100, rect
.left
);
1586 expect(250, rect
.right
);
1588 expect(3, rect
.top
);
1590 rect
.left
= LVIR_BOUNDS
;
1592 rect
.right
= rect
.bottom
= 0;
1593 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1595 ok(r
!= 0, "Expected not-null LRESULT\n");
1596 expect(250, rect
.left
);
1597 expect(450, rect
.right
);
1599 expect(3, rect
.top
);
1601 DestroyWindow(hwnd
);
1603 /* try it for non LVS_REPORT style */
1604 hwnd
= CreateWindow("SysListView32", "Test", LVS_ICON
, 0, 0, 100, 100, NULL
, NULL
,
1605 GetModuleHandle(NULL
), 0);
1606 rect
.left
= LVIR_BOUNDS
;
1608 rect
.right
= rect
.bottom
= -10;
1609 r
= SendMessage(hwnd
, LVM_GETSUBITEMRECT
, -1, (LPARAM
)&rect
);
1610 ok(r
== 0, "Expected not-null LRESULT\n");
1611 /* rect is unchanged */
1612 expect(0, rect
.left
);
1613 expect(-10, rect
.right
);
1614 expect(1, rect
.top
);
1615 expect(-10, rect
.bottom
);
1616 DestroyWindow(hwnd
);
1619 /* comparison callback for test_sorting */
1620 static INT WINAPI
test_CallBackCompare(LPARAM first
, LPARAM second
, LPARAM lParam
)
1622 if (first
== second
) return 0;
1623 return (first
> second
? 1 : -1);
1626 static void test_sorting(void)
1632 static CHAR names
[][4] = {"A", "B", "C", "D"};
1635 hwnd
= create_listview_control(0);
1636 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1638 /* insert some items */
1639 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
1640 item
.state
= LVIS_SELECTED
;
1644 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1647 item
.mask
= LVIF_PARAM
;
1651 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1654 item
.mask
= LVIF_STATE
| LVIF_PARAM
;
1655 item
.state
= LVIS_SELECTED
;
1659 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1662 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1665 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1668 r
= SendMessage(hwnd
, LVM_SORTITEMS
, 0, (LPARAM
)test_CallBackCompare
);
1671 r
= SendMessage(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1673 r
= SendMessage(hwnd
, LVM_GETSELECTIONMARK
, 0, 0);
1675 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 0, LVIS_SELECTED
);
1677 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 1, LVIS_SELECTED
);
1678 expect(LVIS_SELECTED
, r
);
1679 r
= SendMessage(hwnd
, LVM_GETITEMSTATE
, 2, LVIS_SELECTED
);
1680 expect(LVIS_SELECTED
, r
);
1682 DestroyWindow(hwnd
);
1684 /* switch to LVS_SORTASCENDING when some items added */
1685 hwnd
= create_listview_control(0);
1686 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1688 item
.mask
= LVIF_TEXT
;
1691 item
.pszText
= names
[1];
1692 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1695 item
.mask
= LVIF_TEXT
;
1698 item
.pszText
= names
[2];
1699 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1702 item
.mask
= LVIF_TEXT
;
1705 item
.pszText
= names
[0];
1706 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1709 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1710 SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_SORTASCENDING
);
1711 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1712 ok(style
& LVS_SORTASCENDING
, "Expected LVS_SORTASCENDING to be set\n");
1714 /* no sorting performed when switched to LVS_SORTASCENDING */
1715 item
.mask
= LVIF_TEXT
;
1717 item
.pszText
= buff
;
1718 item
.cchTextMax
= sizeof(buff
);
1719 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1721 ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
1724 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1726 ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
1729 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1731 ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
1733 /* adding new item doesn't resort list */
1734 item
.mask
= LVIF_TEXT
;
1737 item
.pszText
= names
[3];
1738 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
1741 item
.mask
= LVIF_TEXT
;
1743 item
.pszText
= buff
;
1744 item
.cchTextMax
= sizeof(buff
);
1745 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1747 todo_wine
ok(lstrcmp(buff
, names
[1]) == 0, "Expected '%s', got '%s'\n", names
[1], buff
);
1750 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1752 todo_wine
ok(lstrcmp(buff
, names
[2]) == 0, "Expected '%s', got '%s'\n", names
[2], buff
);
1755 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1757 todo_wine
ok(lstrcmp(buff
, names
[0]) == 0, "Expected '%s', got '%s'\n", names
[0], buff
);
1760 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
1762 ok(lstrcmp(buff
, names
[3]) == 0, "Expected '%s', got '%s'\n", names
[3], buff
);
1764 DestroyWindow(hwnd
);
1767 static void test_ownerdata(void)
1770 LONG_PTR style
, ret
;
1774 /* it isn't possible to set LVS_OWNERDATA after creation */
1775 hwnd
= create_listview_control(0);
1776 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1777 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1778 ok(!(style
& LVS_OWNERDATA
) && style
, "LVS_OWNERDATA isn't expected\n");
1780 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1782 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1783 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1784 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1785 "try to switch to LVS_OWNERDATA seq", FALSE
);
1787 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1788 ok(!(style
& LVS_OWNERDATA
), "LVS_OWNERDATA isn't expected\n");
1789 DestroyWindow(hwnd
);
1791 /* try to set LVS_OWNERDATA after creation just having it */
1792 hwnd
= create_listview_control(LVS_OWNERDATA
);
1793 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1794 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1795 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1797 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1799 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
| LVS_OWNERDATA
);
1800 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1801 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1802 "try to switch to LVS_OWNERDATA seq", FALSE
);
1803 DestroyWindow(hwnd
);
1805 /* try to remove LVS_OWNERDATA after creation just having it */
1806 hwnd
= create_listview_control(LVS_OWNERDATA
);
1807 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1808 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1809 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1811 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1813 ret
= SetWindowLongPtrA(hwnd
, GWL_STYLE
, style
& ~LVS_OWNERDATA
);
1814 ok(ret
== style
, "Expected set GWL_STYLE to succeed\n");
1815 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_ownerdata_switchto_seq
,
1816 "try to switch to LVS_OWNERDATA seq", FALSE
);
1817 style
= GetWindowLongPtrA(hwnd
, GWL_STYLE
);
1818 ok(style
& LVS_OWNERDATA
, "LVS_OWNERDATA is expected\n");
1819 DestroyWindow(hwnd
);
1821 /* try select an item */
1822 hwnd
= create_listview_control(LVS_OWNERDATA
);
1823 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1824 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1825 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1826 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1828 memset(&item
, 0, sizeof(item
));
1829 item
.stateMask
= LVIS_SELECTED
;
1830 item
.state
= LVIS_SELECTED
;
1831 res
= SendMessageA(hwnd
, LVM_SETITEMSTATE
, 0, (LPARAM
)&item
);
1833 res
= SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, 0, 0);
1835 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1837 DestroyWindow(hwnd
);
1839 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
1840 hwnd
= create_listview_control(LVS_OWNERDATA
);
1841 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1842 res
= SendMessageA(hwnd
, LVM_SETITEMCOUNT
, 1, 0);
1843 ok(res
!= 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1844 res
= SendMessageA(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
1846 memset(&item
, 0, sizeof(item
));
1847 item
.mask
= LVIF_STATE
;
1849 item
.stateMask
= LVIS_SELECTED
;
1850 item
.state
= LVIS_SELECTED
;
1851 res
= SendMessageA(hwnd
, LVM_SETITEM
, 0, (LPARAM
)&item
);
1853 DestroyWindow(hwnd
);
1856 static void test_norecompute(void)
1858 static CHAR testA
[] = "test";
1864 /* self containing control */
1865 hwnd
= create_listview_control(0);
1866 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1867 memset(&item
, 0, sizeof(item
));
1868 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
1870 item
.stateMask
= LVIS_SELECTED
;
1871 item
.state
= LVIS_SELECTED
;
1872 item
.pszText
= testA
;
1873 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
1875 /* retrieve with LVIF_NORECOMPUTE */
1876 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
1878 item
.pszText
= buff
;
1879 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
1880 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
1882 ok(lstrcmp(buff
, testA
) == 0, "Expected (%s), got (%s)\n", testA
, buff
);
1884 item
.mask
= LVIF_TEXT
;
1886 item
.pszText
= LPSTR_TEXTCALLBACK
;
1887 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
1890 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
1892 item
.pszText
= buff
;
1893 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
1895 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1896 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
1898 ok(item
.pszText
== LPSTR_TEXTCALLBACK
, "Expected (%p), got (%p)\n",
1899 LPSTR_TEXTCALLBACK
, (VOID
*)item
.pszText
);
1900 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "retrieve with LVIF_NORECOMPUTE seq", FALSE
);
1902 DestroyWindow(hwnd
);
1905 hwnd
= create_listview_control(LVS_OWNERDATA
);
1906 ok(hwnd
!= NULL
, "failed to create a listview window\n");
1908 item
.mask
= LVIF_STATE
;
1909 item
.stateMask
= LVIS_SELECTED
;
1910 item
.state
= LVIS_SELECTED
;
1912 res
= SendMessageA(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
)&item
);
1915 item
.mask
= LVIF_TEXT
| LVIF_NORECOMPUTE
;
1917 item
.pszText
= buff
;
1918 item
.cchTextMax
= sizeof(buff
)/sizeof(CHAR
);
1919 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1920 res
= SendMessageA(hwnd
, LVM_GETITEM
, 0, (LPARAM
)&item
);
1922 ok(item
.pszText
== LPSTR_TEXTCALLBACK
, "Expected (%p), got (%p)\n",
1923 LPSTR_TEXTCALLBACK
, (VOID
*)item
.pszText
);
1924 ok_sequence(sequences
, PARENT_SEQ_INDEX
, empty_seq
, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE
);
1926 DestroyWindow(hwnd
);
1929 START_TEST(listview
)
1932 BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
1934 hComctl32
= GetModuleHandleA("comctl32.dll");
1935 pInitCommonControlsEx
= (void*)GetProcAddress(hComctl32
, "InitCommonControlsEx");
1936 if (pInitCommonControlsEx
)
1938 INITCOMMONCONTROLSEX iccex
;
1939 iccex
.dwSize
= sizeof(iccex
);
1940 iccex
.dwICC
= ICC_LISTVIEW_CLASSES
;
1941 pInitCommonControlsEx(&iccex
);
1944 InitCommonControls();
1946 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1948 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1949 hwndparent
= create_parent_window();
1950 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent window", TRUE
);
1951 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1959 test_icon_spacing();
1962 test_item_position();
1966 test_subitem_rect();