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_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
52 { WM_ACTIVATEAPP
, sent
|wparam
, 1 },
53 { WM_NCACTIVATE
, sent
|wparam
, 1 },
54 { WM_ACTIVATE
, sent
|wparam
, 1 },
55 { WM_IME_SETCONTEXT
, sent
|wparam
|defwinproc
|optional
, 1 },
56 { WM_IME_NOTIFY
, sent
|defwinproc
|optional
},
57 { WM_SETFOCUS
, sent
|wparam
|defwinproc
, 0 },
58 /* Win9x adds SWP_NOZORDER below */
59 { WM_WINDOWPOSCHANGED
, sent
, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
60 { WM_NCCALCSIZE
, sent
|wparam
|optional
, 1 },
66 static const struct message redraw_listview_seq
[] = {
67 { WM_PAINT
, sent
|id
, 0, 0, LISTVIEW_ID
},
68 { WM_PAINT
, sent
|id
, 0, 0, HEADER_ID
},
69 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
70 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, HEADER_ID
},
71 { WM_NOTIFY
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
72 { WM_NCPAINT
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
73 { WM_ERASEBKGND
, sent
|id
|defwinproc
, 0, 0, LISTVIEW_ID
},
77 static const struct message listview_icon_spacing_seq
[] = {
78 { LVM_SETICONSPACING
, sent
|lparam
, 0, (LPARAM
) MAKELONG(20, 30) },
79 { LVM_SETICONSPACING
, sent
|lparam
, 0, (LPARAM
) MAKELONG(25, 35) },
80 { LVM_SETICONSPACING
, sent
|lparam
, 0, (LPARAM
) MAKELONG(-1, -1) },
84 static const struct message listview_color_seq
[] = {
85 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
86 { LVM_GETBKCOLOR
, sent
},
87 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
88 { LVM_GETTEXTCOLOR
, sent
},
89 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(0,0,0) },
90 { LVM_GETTEXTBKCOLOR
, sent
},
92 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
93 { LVM_GETBKCOLOR
, sent
},
94 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
95 { LVM_GETTEXTCOLOR
, sent
},
96 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(100,50,200) },
97 { LVM_GETTEXTBKCOLOR
, sent
},
99 { LVM_SETBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
100 { LVM_GETBKCOLOR
, sent
},
101 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, CLR_NONE
},
102 { LVM_GETTEXTCOLOR
, sent
},
103 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, CLR_NONE
},
104 { LVM_GETTEXTBKCOLOR
, sent
},
106 { LVM_SETBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
107 { LVM_GETBKCOLOR
, sent
},
108 { LVM_SETTEXTCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
109 { LVM_GETTEXTCOLOR
, sent
},
110 { LVM_SETTEXTBKCOLOR
, sent
|lparam
, 0, RGB(255,255,255) },
111 { LVM_GETTEXTBKCOLOR
, sent
},
115 static const struct message listview_item_count_seq
[] = {
116 { LVM_GETITEMCOUNT
, sent
},
117 { LVM_INSERTITEM
, sent
},
118 { LVM_INSERTITEM
, sent
},
119 { LVM_INSERTITEM
, sent
},
120 { LVM_GETITEMCOUNT
, sent
},
121 { LVM_DELETEITEM
, sent
|wparam
, 2 },
122 { LVM_GETITEMCOUNT
, sent
},
123 { LVM_DELETEALLITEMS
, sent
},
124 { LVM_GETITEMCOUNT
, sent
},
125 { LVM_INSERTITEM
, sent
},
126 { LVM_INSERTITEM
, sent
},
127 { LVM_GETITEMCOUNT
, sent
},
128 { LVM_INSERTITEM
, sent
},
129 { LVM_GETITEMCOUNT
, sent
},
133 static const struct message listview_itempos_seq
[] = {
134 { LVM_INSERTITEM
, sent
},
135 { LVM_INSERTITEM
, sent
},
136 { LVM_INSERTITEM
, sent
},
137 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 1, MAKELPARAM(10,5) },
138 { LVM_GETITEMPOSITION
, sent
|wparam
, 1 },
139 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 2, MAKELPARAM(0,0) },
140 { LVM_GETITEMPOSITION
, sent
|wparam
, 2 },
141 { LVM_SETITEMPOSITION
, sent
|wparam
|lparam
, 0, MAKELPARAM(20,20) },
142 { LVM_GETITEMPOSITION
, sent
|wparam
, 0 },
151 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
153 static long defwndproc_counter
= 0;
157 /* do not log painting messages */
158 if (message
!= WM_PAINT
&&
159 message
!= WM_ERASEBKGND
&&
160 message
!= WM_NCPAINT
&&
161 message
!= WM_NCHITTEST
&&
162 message
!= WM_GETTEXT
&&
163 message
!= WM_GETICON
&&
164 message
!= WM_DEVICECHANGE
)
166 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
168 msg
.message
= message
;
169 msg
.flags
= sent
|wparam
|lparam
;
170 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
173 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
176 defwndproc_counter
++;
177 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
178 defwndproc_counter
--;
183 static BOOL
register_parent_wnd_class(void)
188 cls
.lpfnWndProc
= parent_wnd_proc
;
191 cls
.hInstance
= GetModuleHandleA(NULL
);
193 cls
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
194 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
195 cls
.lpszMenuName
= NULL
;
196 cls
.lpszClassName
= "Listview test parent class";
197 return RegisterClassA(&cls
);
200 static HWND
create_parent_window(void)
202 if (!register_parent_wnd_class())
205 return CreateWindowEx(0, "Listview test parent class",
206 "Listview test parent window",
207 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
208 WS_MAXIMIZEBOX
| WS_VISIBLE
,
210 GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
213 static LRESULT WINAPI
listview_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
215 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
216 static long defwndproc_counter
= 0;
220 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
222 msg
.message
= message
;
223 msg
.flags
= sent
|wparam
|lparam
;
224 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
227 msg
.id
= LISTVIEW_ID
;
228 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
230 defwndproc_counter
++;
231 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
232 defwndproc_counter
--;
236 static HWND
create_listview_control(void)
238 struct subclass_info
*info
;
242 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
246 GetClientRect(hwndparent
, &rect
);
247 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
248 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| LVS_REPORT
,
249 0, 0, rect
.right
, rect
.bottom
,
250 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
251 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
255 HeapFree(GetProcessHeap(), 0, info
);
259 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
260 (LONG_PTR
)listview_subclass_proc
);
261 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
266 static HWND
create_custom_listview_control(DWORD style
)
268 struct subclass_info
*info
;
272 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
276 GetClientRect(hwndparent
, &rect
);
277 hwnd
= CreateWindowExA(0, WC_LISTVIEW
, "foo",
278 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
279 0, 0, rect
.right
, rect
.bottom
,
280 hwndparent
, NULL
, GetModuleHandleA(NULL
), NULL
);
281 ok(hwnd
!= NULL
, "gle=%d\n", GetLastError());
285 HeapFree(GetProcessHeap(), 0, info
);
289 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
290 (LONG_PTR
)listview_subclass_proc
);
291 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
296 static LRESULT WINAPI
header_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
298 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
299 static long defwndproc_counter
= 0;
303 trace("header: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
305 msg
.message
= message
;
306 msg
.flags
= sent
|wparam
|lparam
;
307 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
311 add_message(sequences
, LISTVIEW_SEQ_INDEX
, &msg
);
313 defwndproc_counter
++;
314 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
315 defwndproc_counter
--;
319 static HWND
subclass_header(HWND hwndListview
)
321 struct subclass_info
*info
;
324 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
328 hwnd
= ListView_GetHeader(hwndListview
);
329 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
,
330 (LONG_PTR
)header_subclass_proc
);
331 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)info
);
336 static void test_images(void)
344 static CHAR hello
[] = "hello";
346 himl
= ImageList_Create(40, 40, 0, 4, 4);
347 ok(himl
!= NULL
, "failed to create imagelist\n");
349 hbmp
= CreateBitmap(40, 40, 1, 1, NULL
);
350 ok(hbmp
!= NULL
, "failed to create bitmap\n");
352 r
= ImageList_Add(himl
, hbmp
, 0);
353 ok(r
== 0, "should be zero\n");
355 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED
,
356 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
357 ok(hwnd
!= NULL
, "failed to create listview window\n");
359 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, 0x940);
360 ok(r
== 0, "should return zero\n");
362 r
= SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)himl
);
363 ok(r
== 0, "should return zero\n");
365 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, MAKELONG(100,50));
366 /* returns dimensions */
368 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
369 ok(r
== 0, "should be zero items\n");
371 item
.mask
= LVIF_IMAGE
| LVIF_TEXT
;
376 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
377 ok(r
== -1, "should fail\n");
380 item
.pszText
= hello
;
381 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
382 ok(r
== 0, "should not fail\n");
384 memset(&r1
, 0, sizeof r1
);
386 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r1
);
388 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
389 ok(r
== TRUE
, "should not fail\n");
392 item
.pszText
= hello
;
393 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item
);
394 ok(r
== 0, "should not fail\n");
396 memset(&r2
, 0, sizeof r2
);
398 r
= SendMessage(hwnd
, LVM_GETITEMRECT
, 0, (LPARAM
) &r2
);
400 ok(!memcmp(&r1
, &r2
, sizeof r1
), "rectangle should be the same\n");
405 static void test_checkboxes(void)
410 static CHAR text
[] = "Text",
414 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
415 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
416 ok(hwnd
!= NULL
, "failed to create listview window\n");
418 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
419 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
420 item
.stateMask
= 0xffff;
425 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
426 ok(r
== 0, "ret %d\n", r
);
429 item
.mask
= LVIF_STATE
;
430 item
.stateMask
= 0xffff;
431 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
432 ok(item
.state
== 0xfccc, "state %x\n", item
.state
);
434 /* Don't set LVIF_STATE */
435 item
.mask
= LVIF_TEXT
;
436 item
.stateMask
= 0xffff;
441 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
442 ok(r
== 1, "ret %d\n", r
);
445 item
.mask
= LVIF_STATE
;
446 item
.stateMask
= 0xffff;
447 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
448 ok(item
.state
== 0, "state %x\n", item
.state
);
450 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
451 ok(r
== 0, "should return zero\n");
453 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
455 item
.mask
= LVIF_STATE
;
456 item
.stateMask
= 0xffff;
457 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
458 ok(item
.state
== 0x1ccc, "state %x\n", item
.state
);
460 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
462 item
.mask
= LVIF_TEXT
;
464 item
.pszText
= text2
;
465 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
466 ok(r
== 2, "ret %d\n", r
);
469 item
.mask
= LVIF_STATE
;
470 item
.stateMask
= 0xffff;
471 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
472 ok(item
.state
== 0x1000, "state %x\n", item
.state
);
474 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
476 item
.mask
= LVIF_TEXT
| LVIF_STATE
;
477 item
.stateMask
= 0xffff;
479 item
.pszText
= text3
;
480 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
481 ok(r
== 3, "ret %d\n", r
);
484 item
.mask
= LVIF_STATE
;
485 item
.stateMask
= 0xffff;
486 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
487 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
489 /* Set an item's state to checked */
491 item
.mask
= LVIF_STATE
;
492 item
.stateMask
= 0xf000;
494 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
497 item
.mask
= LVIF_STATE
;
498 item
.stateMask
= 0xffff;
499 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
500 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
502 /* Check that only the bits we asked for are returned,
503 * and that all the others are set to zero
506 item
.mask
= LVIF_STATE
;
507 item
.stateMask
= 0xf000;
509 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
510 ok(item
.state
== 0x2000, "state %x\n", item
.state
);
512 /* Set the style again and check that doesn't change an item's state */
513 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
514 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
517 item
.mask
= LVIF_STATE
;
518 item
.stateMask
= 0xffff;
519 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
520 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
522 /* Unsetting the checkbox extended style doesn't change an item's state */
523 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, 0);
524 ok(r
== LVS_EX_CHECKBOXES
, "ret %x\n", r
);
527 item
.mask
= LVIF_STATE
;
528 item
.stateMask
= 0xffff;
529 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
530 ok(item
.state
== 0x2aaa, "state %x\n", item
.state
);
532 /* Now setting the style again will change an item's state */
533 r
= SendMessage(hwnd
, LVM_SETEXTENDEDLISTVIEWSTYLE
, LVS_EX_CHECKBOXES
, LVS_EX_CHECKBOXES
);
534 ok(r
== 0, "ret %x\n", r
);
537 item
.mask
= LVIF_STATE
;
538 item
.stateMask
= 0xffff;
539 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
540 ok(item
.state
== 0x1aaa, "state %x\n", item
.state
);
545 static void insert_column(HWND hwnd
, int idx
)
550 memset(&column
, 0xaa, sizeof(column
));
551 column
.mask
= LVCF_SUBITEM
;
552 column
.iSubItem
= idx
;
554 rc
= ListView_InsertColumn(hwnd
, idx
, &column
);
558 static void insert_item(HWND hwnd
, int idx
)
560 static CHAR text
[] = "foo";
565 memset(&item
, 0xaa, sizeof (item
));
566 item
.mask
= LVIF_TEXT
;
571 rc
= ListView_InsertItem(hwnd
, &item
);
575 static void test_items(void)
577 const LPARAM lparamTest
= 0x42;
581 static CHAR text
[] = "Text";
583 hwnd
= CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT
,
584 10, 10, 100, 200, hwndparent
, NULL
, NULL
, NULL
);
585 ok(hwnd
!= NULL
, "failed to create listview window\n");
588 * Test setting/getting item params
591 /* Set up two columns */
592 insert_column(hwnd
, 0);
593 insert_column(hwnd
, 1);
595 /* Insert an item with just a param */
596 memset (&item
, 0xaa, sizeof (item
));
597 item
.mask
= LVIF_PARAM
;
600 item
.lParam
= lparamTest
;
601 r
= SendMessage(hwnd
, LVM_INSERTITEMA
, 0, (LPARAM
) &item
);
602 ok(r
== 0, "ret %d\n", r
);
604 /* Test getting of the param */
605 memset (&item
, 0xaa, sizeof (item
));
606 item
.mask
= LVIF_PARAM
;
609 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
610 ok(r
!= 0, "ret %d\n", r
);
611 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
613 /* Set up a subitem */
614 memset (&item
, 0xaa, sizeof (item
));
615 item
.mask
= LVIF_TEXT
;
619 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
620 ok(r
!= 0, "ret %d\n", r
);
622 /* Query param from subitem: returns main item param */
623 memset (&item
, 0xaa, sizeof (item
));
624 item
.mask
= LVIF_PARAM
;
627 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
628 ok(r
!= 0, "ret %d\n", r
);
629 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
631 /* Set up param on first subitem: no effect */
632 memset (&item
, 0xaa, sizeof (item
));
633 item
.mask
= LVIF_PARAM
;
636 item
.lParam
= lparamTest
+1;
637 r
= SendMessage(hwnd
, LVM_SETITEMA
, 0, (LPARAM
) &item
);
638 ok(r
== 0, "ret %d\n", r
);
640 /* Query param from subitem again: should still return main item param */
641 memset (&item
, 0xaa, sizeof (item
));
642 item
.mask
= LVIF_PARAM
;
645 r
= SendMessage(hwnd
, LVM_GETITEMA
, 0, (LPARAM
) &item
);
646 ok(r
!= 0, "ret %d\n", r
);
647 ok(item
.lParam
== lparamTest
, "got lParam %lx, expected %lx\n", item
.lParam
, lparamTest
);
649 /**** Some tests of state highlighting ****/
650 memset (&item
, 0xaa, sizeof (item
));
651 item
.mask
= LVIF_STATE
;
654 item
.state
= LVIS_SELECTED
;
655 item
.stateMask
= LVIS_SELECTED
| LVIS_DROPHILITED
;
656 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
657 ok(r
!= 0, "ret %d\n", r
);
659 item
.state
= LVIS_DROPHILITED
;
660 r
= SendMessage(hwnd
, LVM_SETITEM
, 0, (LPARAM
) &item
);
661 ok(r
!= 0, "ret %d\n", r
);
663 memset (&item
, 0xaa, sizeof (item
));
664 item
.mask
= LVIF_STATE
;
668 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
669 ok(r
!= 0, "ret %d\n", r
);
670 ok(item
.state
== LVIS_SELECTED
, "got state %x, expected %x\n", item
.state
, LVIS_SELECTED
);
672 r
= SendMessage(hwnd
, LVM_GETITEM
, 0, (LPARAM
) &item
);
673 ok(r
!= 0, "ret %d\n", r
);
674 todo_wine
ok(item
.state
== LVIS_DROPHILITED
, "got state %x, expected %x\n", item
.state
, LVIS_DROPHILITED
);
679 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
680 static WNDPROC listviewWndProc
;
681 static HIMAGELIST test_create_imagelist
;
683 static LRESULT CALLBACK
create_test_wndproc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
685 if (uMsg
== WM_CREATE
)
687 LPCREATESTRUCT lpcs
= (LPCREATESTRUCT
)lParam
;
688 lpcs
->style
|= LVS_REPORT
;
689 SendMessage(hwnd
, LVM_SETIMAGELIST
, 0, (LPARAM
)test_create_imagelist
);
691 return CallWindowProc(listviewWndProc
, hwnd
, uMsg
, wParam
, lParam
);
694 static void test_create(void)
699 cls
.cbSize
= sizeof(WNDCLASSEX
);
700 ok(GetClassInfoEx(GetModuleHandle(NULL
), "SysListView32", &cls
), "GetClassInfoEx failed\n");
701 listviewWndProc
= cls
.lpfnWndProc
;
702 cls
.lpfnWndProc
= create_test_wndproc
;
703 cls
.lpszClassName
= "MyListView32";
704 ok(RegisterClassEx(&cls
), "RegisterClassEx failed\n");
706 test_create_imagelist
= ImageList_Create(16, 16, 0, 5, 10);
707 hList
= CreateWindow("MyListView32", "Test", WS_VISIBLE
, 0, 0, 100, 100, NULL
, NULL
, GetModuleHandle(NULL
), 0);
708 ok((HIMAGELIST
)SendMessage(hList
, LVM_GETIMAGELIST
, 0, 0) == test_create_imagelist
, "Image list not obtained\n");
709 hHeader
= (HWND
)SendMessage(hList
, LVM_GETHEADER
, 0, 0);
710 ok(IsWindow(hHeader
) && IsWindowVisible(hHeader
), "Listview not in report mode\n");
711 DestroyWindow(hList
);
714 static void test_redraw(void)
716 HWND hwnd
, hwndheader
;
718 hwnd
= create_listview_control();
719 hwndheader
= subclass_header(hwnd
);
721 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
723 trace("invalidate & update\n");
724 InvalidateRect(hwnd
, NULL
, TRUE
);
726 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, redraw_listview_seq
, "redraw listview", FALSE
);
728 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
733 static LRESULT WINAPI
cd_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
735 COLORREF clr
, c0ffee
= RGB(0xc0, 0xff, 0xee);
737 if(msg
== WM_NOTIFY
) {
738 NMHDR
*nmhdr
= (PVOID
)lp
;
739 if(nmhdr
->code
== NM_CUSTOMDRAW
) {
740 NMLVCUSTOMDRAW
*nmlvcd
= (PVOID
)nmhdr
;
741 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd
->nmcd
.dwDrawStage
);
742 switch(nmlvcd
->nmcd
.dwDrawStage
) {
744 SetBkColor(nmlvcd
->nmcd
.hdc
, c0ffee
);
745 return CDRF_NOTIFYITEMDRAW
;
746 case CDDS_ITEMPREPAINT
:
747 nmlvcd
->clrTextBk
= CLR_DEFAULT
;
748 return CDRF_NOTIFYSUBITEMDRAW
;
749 case CDDS_ITEMPREPAINT
| CDDS_SUBITEM
:
750 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
751 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
752 return CDRF_NOTIFYPOSTPAINT
;
753 case CDDS_ITEMPOSTPAINT
| CDDS_SUBITEM
:
754 clr
= GetBkColor(nmlvcd
->nmcd
.hdc
);
755 todo_wine
ok(clr
== c0ffee
, "clr=%.8x\n", clr
);
756 return CDRF_DODEFAULT
;
758 return CDRF_DODEFAULT
;
762 return DefWindowProcA(hwnd
, msg
, wp
, lp
);
765 static void test_customdraw(void)
770 hwnd
= create_listview_control();
772 insert_column(hwnd
, 0);
773 insert_column(hwnd
, 1);
774 insert_item(hwnd
, 0);
776 oldwndproc
= (WNDPROC
)SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
,
777 (LONG_PTR
)cd_wndproc
);
779 InvalidateRect(hwnd
, NULL
, TRUE
);
782 SetWindowLongPtr(hwndparent
, GWLP_WNDPROC
, (LONG_PTR
)oldwndproc
);
787 static void test_icon_spacing(void)
789 /* LVM_SETICONSPACING */
790 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
791 /* note: the first test will fail if the default icon spacing is not (43,43) */
796 hwnd
= create_custom_listview_control(LVS_ICON
);
797 ok(hwnd
!= NULL
, "failed to create a listview window\n");
799 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
801 trace("test icon spacing\n");
803 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, (LPARAM
) MAKELONG(20, 30));
804 expect(MAKELONG(43,43), r
);
806 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, (LPARAM
) MAKELONG(25, 35));
807 expect(MAKELONG(20,30), r
);
808 r
= SendMessage(hwnd
, LVM_SETICONSPACING
, 0, (LPARAM
) MAKELONG(-1,-1));
809 expect(MAKELONG(25,35), r
);
811 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_icon_spacing_seq
, "test icon spacing seq", FALSE
);
813 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
817 static void test_color(void)
819 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
826 COLORREF colors
[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE
, RGB(255,255,255)};
828 hwnd
= create_listview_control();
829 ok(hwnd
!= NULL
, "failed to create a listview window\n");
831 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
833 trace("test color seq\n");
834 for (i
= 0; i
< 4; i
++)
838 r
= SendMessage(hwnd
, LVM_SETBKCOLOR
, 0, color
);
840 r
= SendMessage(hwnd
, LVM_GETBKCOLOR
, 0, color
);
843 r
= SendMessage(hwnd
, LVM_SETTEXTCOLOR
, 0, color
);
845 r
= SendMessage(hwnd
, LVM_GETTEXTCOLOR
, 0, color
);
848 r
= SendMessage(hwnd
, LVM_SETTEXTBKCOLOR
, 0, color
);
850 r
= SendMessage(hwnd
, LVM_GETTEXTBKCOLOR
, 0, color
);
854 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_color_seq
, "test color seq", FALSE
);
856 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
860 static void test_item_count(void)
862 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
870 static CHAR item0text
[] = "item0";
871 static CHAR item1text
[] = "item1";
872 static CHAR item2text
[] = "item2";
874 hwnd
= create_listview_control();
875 ok(hwnd
!= NULL
, "failed to create a listview window\n");
877 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
879 trace("test item count\n");
881 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
885 item0
.mask
= LVIF_TEXT
;
888 item0
.pszText
= item0text
;
889 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
893 item1
.mask
= LVIF_TEXT
;
896 item1
.pszText
= item1text
;
897 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
900 /* [item0, item1, item2] */
901 item2
.mask
= LVIF_TEXT
;
904 item2
.pszText
= item2text
;
905 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
908 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
912 r
= SendMessage(hwnd
, LVM_DELETEITEM
, (WPARAM
) 2, 0);
915 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
919 r
= SendMessage(hwnd
, LVM_DELETEALLITEMS
, 0, 0);
922 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
926 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
930 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
933 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
936 /* [item0, item1, item2] */
937 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
940 r
= SendMessage(hwnd
, LVM_GETITEMCOUNT
, 0, 0);
943 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_item_count_seq
, "test item count seq", FALSE
);
945 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
949 static void test_item_position(void)
951 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
960 static CHAR item0text
[] = "item0";
961 static CHAR item1text
[] = "item1";
962 static CHAR item2text
[] = "item2";
964 hwnd
= create_custom_listview_control(LVS_ICON
);
965 ok(hwnd
!= NULL
, "failed to create a listview window\n");
967 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
969 trace("test item position\n");
972 item0
.mask
= LVIF_TEXT
;
975 item0
.pszText
= item0text
;
976 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item0
);
980 item1
.mask
= LVIF_TEXT
;
983 item1
.pszText
= item1text
;
984 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item1
);
987 /* [item0, item1, item2] */
988 item2
.mask
= LVIF_TEXT
;
991 item2
.pszText
= item2text
;
992 r
= SendMessage(hwnd
, LVM_INSERTITEM
, 0, (LPARAM
) &item2
);
995 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 1, MAKELPARAM(10,5));
997 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 1, (LPARAM
) &position
);
999 expect2(10, 5, position
.x
, position
.y
);
1001 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 2, MAKELPARAM(0,0));
1003 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 2, (LPARAM
) &position
);
1005 expect2(0, 0, position
.x
, position
.y
);
1007 r
= SendMessage(hwnd
, LVM_SETITEMPOSITION
, 0, MAKELPARAM(20,20));
1009 r
= SendMessage(hwnd
, LVM_GETITEMPOSITION
, 0, (LPARAM
) &position
);
1011 expect2(20, 20, position
.x
, position
.y
);
1013 ok_sequence(sequences
, LISTVIEW_SEQ_INDEX
, listview_itempos_seq
, "test item position seq", TRUE
);
1015 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1016 DestroyWindow(hwnd
);
1019 START_TEST(listview
)
1021 INITCOMMONCONTROLSEX icc
;
1024 icc
.dwSize
= sizeof icc
;
1025 InitCommonControlsEx(&icc
);
1027 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1029 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1030 hwndparent
= create_parent_window();
1031 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent window", TRUE
);
1032 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1040 test_icon_spacing();
1043 test_item_position();