push 22b3e00525a9a3743634eb8f21ffe1bf98bf885e
[wine/hacks.git] / dlls / comctl32 / tests / listview.c
blob7be6b71592fcfda939efafaeebffa283fef2b530
1 /*
2 * ListView tests
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
22 #include <stdio.h>
23 #include <windows.h>
24 #include <commctrl.h>
26 #include "wine/test.h"
27 #include "msg.h"
29 #define PARENT_SEQ_INDEX 0
30 #define LISTVIEW_SEQ_INDEX 1
31 #define NUM_MSG_SEQUENCES 2
33 #define LISTVIEW_ID 0
34 #define HEADER_ID 1
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)
40 HWND hwndparent;
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 },
48 { WM_CREATE, sent },
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 },
64 { WM_SIZE, sent },
65 { WM_MOVE, sent },
66 { 0 }
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 },
77 { 0 }
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) },
84 { 0 }
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 },
115 { 0 }
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 },
133 { 0 }
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 },
146 { 0 }
149 static const struct message listview_ownerdata_switchto_seq[] = {
150 { WM_STYLECHANGING, sent },
151 { WM_STYLECHANGED, sent },
152 { 0 }
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 },
158 { 0 }
161 static const struct message empty_seq[] = {
162 { 0 }
165 struct subclass_info
167 WNDPROC oldproc;
170 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
172 static LONG defwndproc_counter = 0;
173 LRESULT ret;
174 struct message msg;
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;
191 msg.wParam = wParam;
192 msg.lParam = lParam;
193 add_message(sequences, PARENT_SEQ_INDEX, &msg);
196 defwndproc_counter++;
197 ret = DefWindowProcA(hwnd, message, wParam, lParam);
198 defwndproc_counter--;
200 return ret;
203 static BOOL register_parent_wnd_class(void)
205 WNDCLASSA cls;
207 cls.style = 0;
208 cls.lpfnWndProc = parent_wnd_proc;
209 cls.cbClsExtra = 0;
210 cls.cbWndExtra = 0;
211 cls.hInstance = GetModuleHandleA(NULL);
212 cls.hIcon = 0;
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())
223 return NULL;
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,
229 0, 0, 100, 100,
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;
237 LRESULT ret;
238 struct message msg;
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;
253 msg.wParam = wParam;
254 msg.lParam = lParam;
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--;
261 return ret;
264 static HWND create_listview_control(DWORD style)
266 struct subclass_info *info;
267 HWND hwnd;
268 RECT rect;
270 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
271 if (!info)
272 return NULL;
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());
281 if (!hwnd)
283 HeapFree(GetProcessHeap(), 0, info);
284 return NULL;
287 info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
288 (LONG_PTR)listview_subclass_proc);
289 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
291 return hwnd;
294 static HWND create_custom_listview_control(DWORD style)
296 struct subclass_info *info;
297 HWND hwnd;
298 RECT rect;
300 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
301 if (!info)
302 return NULL;
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());
311 if (!hwnd)
313 HeapFree(GetProcessHeap(), 0, info);
314 return NULL;
317 info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
318 (LONG_PTR)listview_subclass_proc);
319 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
321 return hwnd;
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;
328 LRESULT ret;
329 struct message msg;
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;
336 msg.wParam = wParam;
337 msg.lParam = lParam;
338 msg.id = HEADER_ID;
339 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
341 defwndproc_counter++;
342 ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
343 defwndproc_counter--;
344 return ret;
347 static HWND subclass_header(HWND hwndListview)
349 struct subclass_info *info;
350 HWND hwnd;
352 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
353 if (!info)
354 return NULL;
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);
361 return hwnd;
364 static void test_images(void)
366 HWND hwnd;
367 DWORD r;
368 LVITEM item;
369 HIMAGELIST himl;
370 HBITMAP hbmp;
371 RECT r1, r2;
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;
400 item.iItem = 0;
401 item.iSubItem = 1;
402 item.iImage = 0;
403 item.pszText = 0;
404 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
405 ok(r == -1, "should fail\n");
407 item.iSubItem = 0;
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);
413 r1.left = LVIR_ICON;
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");
419 item.iSubItem = 0;
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);
425 r2.left = LVIR_ICON;
426 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
428 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
430 DestroyWindow(hwnd);
433 static void test_checkboxes(void)
435 HWND hwnd;
436 LVITEMA item;
437 DWORD r;
438 static CHAR text[] = "Text",
439 text2[] = "Text2",
440 text3[] = "Text3";
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;
449 item.state = 0xfccc;
450 item.iItem = 0;
451 item.iSubItem = 0;
452 item.pszText = text;
453 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
454 ok(r == 0, "ret %d\n", r);
456 item.iItem = 0;
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;
465 item.state = 0xfccc;
466 item.iItem = 1;
467 item.iSubItem = 0;
468 item.pszText = text;
469 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
470 ok(r == 1, "ret %d\n", r);
472 item.iItem = 1;
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) */
482 item.iItem = 0;
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 */
489 item.iItem = 2;
490 item.mask = LVIF_TEXT;
491 item.state = 0;
492 item.pszText = text2;
493 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
494 ok(r == 2, "ret %d\n", r);
496 item.iItem = 2;
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 */
503 item.iItem = 3;
504 item.mask = LVIF_TEXT | LVIF_STATE;
505 item.stateMask = 0xffff;
506 item.state = 0x2aaa;
507 item.pszText = text3;
508 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
509 ok(r == 3, "ret %d\n", r);
511 item.iItem = 3;
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 */
518 item.iItem = 3;
519 item.mask = LVIF_STATE;
520 item.stateMask = 0xf000;
521 item.state = 0x2000;
522 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
524 item.iItem = 3;
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
533 item.iItem = 3;
534 item.mask = LVIF_STATE;
535 item.stateMask = 0xf000;
536 item.state = 0xffff;
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);
544 item.iItem = 3;
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);
554 item.iItem = 3;
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);
564 item.iItem = 3;
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;
573 item.iItem = 3;
574 item.iSubItem = 0;
575 item.state = LVIS_FOCUSED;
576 item.stateMask = LVIS_FOCUSED;
577 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
578 expect(1, r);
580 item.iItem = 3;
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);
587 expect(0, r);
588 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
589 expect(0, r);
591 item.iItem = 3;
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);
598 expect(0, r);
599 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
600 expect(0, r);
602 item.iItem = 3;
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);
608 DestroyWindow(hwnd);
611 static void insert_column(HWND hwnd, int idx)
613 LVCOLUMN column;
614 DWORD rc;
616 memset(&column, 0xcc, sizeof(column));
617 column.mask = LVCF_SUBITEM;
618 column.iSubItem = idx;
620 rc = ListView_InsertColumn(hwnd, idx, &column);
621 expect(idx, rc);
624 static void insert_item(HWND hwnd, int idx)
626 static CHAR text[] = "foo";
628 LVITEMA item;
629 DWORD rc;
631 memset(&item, 0xcc, sizeof (item));
632 item.mask = LVIF_TEXT;
633 item.iItem = idx;
634 item.iSubItem = 0;
635 item.pszText = text;
637 rc = ListView_InsertItem(hwnd, &item);
638 expect(idx, rc);
641 static void test_items(void)
643 const LPARAM lparamTest = 0x42;
644 HWND hwnd;
645 LVITEMA item;
646 DWORD r;
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 */
662 /* set */
663 memset (&item, 0, sizeof (item));
664 item.mask = LVIF_STATE;
665 item.state = LVIS_SELECTED;
666 item.stateMask = 0;
667 item.iItem = 0;
668 item.iSubItem = 0;
669 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
670 ok(r == 0, "ret %d\n", r);
671 /* get */
672 memset (&item, 0xcc, sizeof (item));
673 item.mask = LVIF_STATE;
674 item.stateMask = LVIS_SELECTED;
675 item.state = 0;
676 item.iItem = 0;
677 item.iSubItem = 0;
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 */
684 /* set */
685 memset (&item, 0, sizeof (item));
686 item.mask = LVIF_STATE;
687 item.state = LVIS_FOCUSED;
688 item.stateMask = 0;
689 item.iItem = 0;
690 item.iSubItem = 0;
691 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
692 ok(r == 0, "ret %d\n", r);
693 /* get */
694 memset (&item, 0xcc, sizeof (item));
695 item.mask = LVIF_STATE;
696 item.stateMask = LVIS_FOCUSED;
697 item.state = 0;
698 item.iItem = 0;
699 item.iSubItem = 0;
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 */
706 /* set */
707 memset (&item, 0, sizeof (item));
708 item.mask = LVIF_STATE;
709 item.state = LVIS_CUT;
710 item.stateMask = LVIS_FOCUSED;
711 item.iItem = 0;
712 item.iSubItem = 0;
713 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
714 ok(r == 0, "ret %d\n", r);
715 /* get */
716 memset (&item, 0xcc, sizeof (item));
717 item.mask = LVIF_STATE;
718 item.stateMask = LVIS_CUT;
719 item.state = 0;
720 item.iItem = 0;
721 item.iSubItem = 0;
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;
730 item.iItem = 0;
731 item.iSubItem = 0;
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;
739 item.iItem = 0;
740 item.iSubItem = 0;
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;
748 item.iItem = 0;
749 item.iSubItem = 1;
750 item.pszText = 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;
757 item.iItem = 0;
758 item.iSubItem = 1;
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;
766 item.iItem = 0;
767 item.iSubItem = 1;
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;
775 item.iItem = 0;
776 item.iSubItem = 1;
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;
784 item.iItem = 0;
785 item.iSubItem = 0;
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);
790 item.iSubItem = 1;
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;
797 item.iItem = 0;
798 item.iSubItem = 0;
799 item.stateMask = -1;
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);
803 item.iSubItem = 1;
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;
811 item.iItem = 0;
812 item.iSubItem = 0;
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;
817 item.iItem = 0;
818 item.iSubItem = 0;
819 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
820 ok(r != 0, "ret %d\n", r);
822 DestroyWindow(hwnd);
825 static void test_columns(void)
827 HWND hwnd, hwndheader;
828 LVCOLUMN column;
829 DWORD rc;
830 INT order[2];
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));
838 column.mask = 0;
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);
844 ok(rc==10 ||
845 broken(rc==0), /* win9x */
846 "Inserting column with no mask failed to set width to 10 with %d\n", rc);
848 DestroyWindow(hwnd);
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;
856 column.cx = 100;
857 rc = ListView_InsertColumn(hwnd, 0, &column);
858 ok(rc == 0, "Inserting column failed with %d\n", rc);
860 column.cx = 200;
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);
873 DestroyWindow(hwnd);
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)
881 LRESULT ret;
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);
890 return ret;
893 static void test_create(void)
895 HWND hList;
896 HWND hHeader;
897 LONG_PTR ret;
898 LONG r;
899 LVCOLUMNA col;
900 RECT rect;
901 WNDCLASSEX cls;
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");
923 /* insert column */
924 memset(&col, 0, sizeof(LVCOLUMNA));
925 col.mask = LVCF_WIDTH;
926 col.cx = 100;
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");
939 /* insert column */
940 memset(&col, 0, sizeof(LVCOLUMNA));
941 col.mask = LVCF_WIDTH;
942 col.cx = 100;
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");
987 /* insert column */
988 memset(&col, 0, sizeof(LVCOLUMNA));
989 col.mask = LVCF_WIDTH;
990 col.cx = 100;
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;
1038 rect.top = 1;
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);
1061 UpdateWindow(hwnd);
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) {
1079 case CDDS_PREPAINT:
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)
1103 HWND hwnd;
1104 WNDPROC oldwndproc;
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);
1116 UpdateWindow(hwnd);
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 */
1128 HWND hwnd;
1129 WORD w, h;
1130 DWORD r;
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));
1143 w = LOWORD(r);
1144 h = HIWORD(r);
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 */
1171 HWND hwnd;
1172 DWORD r;
1173 int i;
1175 COLORREF color;
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++)
1186 color = colors[i];
1188 r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
1189 expect(TRUE, r);
1190 r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color);
1191 expect(color, r);
1193 r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
1194 expect (TRUE, r);
1195 r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color);
1196 expect(color, r);
1198 r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1199 expect(TRUE, r);
1200 r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color);
1201 expect(color, r);
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 */
1214 HWND hwnd;
1215 DWORD r;
1217 LVITEM item0;
1218 LVITEM item1;
1219 LVITEM item2;
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);
1232 expect(0, r);
1234 /* [item0] */
1235 item0.mask = LVIF_TEXT;
1236 item0.iItem = 0;
1237 item0.iSubItem = 0;
1238 item0.pszText = item0text;
1239 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1240 expect(0, r);
1242 /* [item0, item1] */
1243 item1.mask = LVIF_TEXT;
1244 item1.iItem = 1;
1245 item1.iSubItem = 0;
1246 item1.pszText = item1text;
1247 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1248 expect(1, r);
1250 /* [item0, item1, item2] */
1251 item2.mask = LVIF_TEXT;
1252 item2.iItem = 2;
1253 item2.iSubItem = 0;
1254 item2.pszText = item2text;
1255 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1256 expect(2, r);
1258 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1259 expect(3, r);
1261 /* [item0, item1] */
1262 r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0);
1263 expect(TRUE, r);
1265 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1266 expect(2, r);
1268 /* [] */
1269 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1270 expect(TRUE, r);
1272 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1273 expect(0, r);
1275 /* [item0] */
1276 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1277 expect(0, r);
1279 /* [item0, item1] */
1280 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1281 expect(1, r);
1283 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1284 expect(2, r);
1286 /* [item0, item1, item2] */
1287 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1288 expect(2, r);
1290 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1291 expect(3, r);
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 */
1303 HWND hwnd;
1304 DWORD r;
1305 POINT position;
1307 LVITEM item0;
1308 LVITEM item1;
1309 LVITEM item2;
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");
1321 /* [item0] */
1322 item0.mask = LVIF_TEXT;
1323 item0.iItem = 0;
1324 item0.iSubItem = 0;
1325 item0.pszText = item0text;
1326 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1327 expect(0, r);
1329 /* [item0, item1] */
1330 item1.mask = LVIF_TEXT;
1331 item1.iItem = 1;
1332 item1.iSubItem = 0;
1333 item1.pszText = item1text;
1334 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1335 expect(1, r);
1337 /* [item0, item1, item2] */
1338 item2.mask = LVIF_TEXT;
1339 item2.iItem = 2;
1340 item2.iSubItem = 0;
1341 item2.pszText = item2text;
1342 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1343 expect(2, r);
1345 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
1346 expect(TRUE, r);
1347 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
1348 expect(TRUE, r);
1349 expect2(10, 5, position.x, position.y);
1351 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
1352 expect(TRUE, r);
1353 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
1354 expect(TRUE, r);
1355 expect2(0, 0, position.x, position.y);
1357 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
1358 expect(TRUE, r);
1359 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
1360 expect(TRUE, r);
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)
1371 /* LVM_GETORIGIN */
1373 HWND hwnd;
1374 DWORD r;
1375 POINT position;
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);
1384 expect(TRUE, r);
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);
1393 expect(TRUE, r);
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);
1402 expect(FALSE, r);
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);
1411 expect(FALSE, r);
1412 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1413 DestroyWindow(hwnd);
1417 static void test_multiselect(void)
1419 typedef struct t_select_task
1421 const char *descr;
1422 int initPos;
1423 int loopVK;
1424 int count;
1425 int result;
1426 } select_task;
1428 HWND hwnd;
1429 DWORD r;
1430 int i,j,item_count,selected_count;
1431 static const int items=5;
1432 BYTE kstate[256];
1433 select_task task;
1434 LONG_PTR style;
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);
1454 for (i=0;i<4;i++) {
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);
1476 expect(0,r);
1477 r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
1478 expect(0,r);
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);
1502 for (i=0;i<3;i++) {
1503 ListView_SetItemState(hwnd, i, LVIS_SELECTED, LVIS_SELECTED);
1506 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1507 expect(3, r);
1508 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1509 todo_wine
1510 expect(-1, r);
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");
1519 for (i=0;i<3;i++) {
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);
1524 expect(3, r);
1525 SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1526 expect(3, r);
1528 /* select one more */
1529 ListView_SetItemState(hwnd, 3, LVIS_SELECTED, LVIS_SELECTED);
1531 for (i=0;i<3;i++) {
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);
1539 expect(1, r);
1540 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1541 todo_wine
1542 expect(-1, r);
1544 DestroyWindow(hwnd);
1547 static void test_subitem_rect(void)
1549 HWND hwnd;
1550 DWORD r;
1551 LVCOLUMN col;
1552 RECT rect;
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;
1560 col.cx = 100;
1561 r = -1;
1562 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1563 expect(0, r);
1564 col.cx = 150;
1565 r = -1;
1566 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
1567 expect(1, r);
1568 col.cx = 200;
1569 r = -1;
1570 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
1571 expect(2, r);
1572 /* item = -1 means header, subitem index is 1 based */
1573 rect.left = LVIR_BOUNDS;
1574 rect.top = 0;
1575 rect.right = rect.bottom = 0;
1576 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1577 expect(0, r);
1579 rect.left = LVIR_BOUNDS;
1580 rect.top = 1;
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);
1587 todo_wine
1588 expect(3, rect.top);
1590 rect.left = LVIR_BOUNDS;
1591 rect.top = 2;
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);
1598 todo_wine
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;
1607 rect.top = 1;
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)
1628 HWND hwnd;
1629 LVITEMA item = {0};
1630 DWORD r;
1631 LONG_PTR style;
1632 static CHAR names[][4] = {"A", "B", "C", "D"};
1633 CHAR buff[10];
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;
1641 item.iItem = 0;
1642 item.iSubItem = 0;
1643 item.lParam = 3;
1644 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1645 expect(0, r);
1647 item.mask = LVIF_PARAM;
1648 item.iItem = 1;
1649 item.iSubItem = 0;
1650 item.lParam = 2;
1651 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1652 expect(1, r);
1654 item.mask = LVIF_STATE | LVIF_PARAM;
1655 item.state = LVIS_SELECTED;
1656 item.iItem = 2;
1657 item.iSubItem = 0;
1658 item.lParam = 4;
1659 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1660 expect(2, r);
1662 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1663 expect(-1, r);
1665 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1666 expect(2, r);
1668 r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
1669 expect(TRUE, r);
1671 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1672 expect(2, r);
1673 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1674 expect(-1, r);
1675 r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
1676 expect(0, r);
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;
1689 item.iItem = 0;
1690 item.iSubItem = 0;
1691 item.pszText = names[1];
1692 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1693 expect(0, r);
1695 item.mask = LVIF_TEXT;
1696 item.iItem = 1;
1697 item.iSubItem = 0;
1698 item.pszText = names[2];
1699 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1700 expect(1, r);
1702 item.mask = LVIF_TEXT;
1703 item.iItem = 2;
1704 item.iSubItem = 0;
1705 item.pszText = names[0];
1706 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1707 expect(2, r);
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;
1716 item.iItem = 0;
1717 item.pszText = buff;
1718 item.cchTextMax = sizeof(buff);
1719 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1720 expect(TRUE, r);
1721 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
1723 item.iItem = 1;
1724 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1725 expect(TRUE, r);
1726 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
1728 item.iItem = 2;
1729 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1730 expect(TRUE, r);
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;
1735 item.iItem = 3;
1736 item.iSubItem = 0;
1737 item.pszText = names[3];
1738 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1739 expect(3, r);
1741 item.mask = LVIF_TEXT;
1742 item.iItem = 0;
1743 item.pszText = buff;
1744 item.cchTextMax = sizeof(buff);
1745 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1746 expect(TRUE, r);
1747 todo_wine ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
1749 item.iItem = 1;
1750 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1751 expect(TRUE, r);
1752 todo_wine ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
1754 item.iItem = 2;
1755 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1756 expect(TRUE, r);
1757 todo_wine ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
1759 item.iItem = 3;
1760 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1761 expect(TRUE, r);
1762 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
1764 DestroyWindow(hwnd);
1767 static void test_ownerdata(void)
1769 HWND hwnd;
1770 LONG_PTR style, ret;
1771 DWORD res;
1772 LVITEMA item;
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);
1827 expect(0, res);
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);
1832 expect(TRUE, res);
1833 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1834 expect(1, res);
1835 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
1836 expect(1, res);
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);
1845 expect(1, res);
1846 memset(&item, 0, sizeof(item));
1847 item.mask = LVIF_STATE;
1848 item.iItem = 0;
1849 item.stateMask = LVIS_SELECTED;
1850 item.state = LVIS_SELECTED;
1851 res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
1852 expect(FALSE, res);
1853 DestroyWindow(hwnd);
1856 static void test_norecompute(void)
1858 static CHAR testA[] = "test";
1859 CHAR buff[10];
1860 LVITEMA item;
1861 HWND hwnd;
1862 DWORD res;
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;
1869 item.iItem = 0;
1870 item.stateMask = LVIS_SELECTED;
1871 item.state = LVIS_SELECTED;
1872 item.pszText = testA;
1873 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
1874 expect(0, res);
1875 /* retrieve with LVIF_NORECOMPUTE */
1876 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
1877 item.iItem = 0;
1878 item.pszText = buff;
1879 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
1880 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
1881 expect(TRUE, res);
1882 ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
1884 item.mask = LVIF_TEXT;
1885 item.iItem = 1;
1886 item.pszText = LPSTR_TEXTCALLBACK;
1887 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
1888 expect(1, res);
1890 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
1891 item.iItem = 1;
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);
1897 expect(TRUE, res);
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);
1904 /* LVS_OWNERDATA */
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;
1911 item.iItem = 0;
1912 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
1913 expect(0, res);
1915 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
1916 item.iItem = 0;
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);
1921 expect(TRUE, res);
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)
1931 HMODULE hComctl32;
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);
1943 else
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);
1953 test_images();
1954 test_checkboxes();
1955 test_items();
1956 test_create();
1957 test_redraw();
1958 test_customdraw();
1959 test_icon_spacing();
1960 test_color();
1961 test_item_count();
1962 test_item_position();
1963 test_columns();
1964 test_getorigin();
1965 test_multiselect();
1966 test_subitem_rect();
1967 test_sorting();
1968 test_ownerdata();
1969 test_norecompute();