push 52d6b63ba2f2d4f9b02b6b922d27bff05a60596f
[wine/hacks.git] / dlls / comctl32 / tests / listview.c
blob44c5eb2c49d8fd3192de52f4e7d8a7c7ecbe39e0
1 /*
2 * ListView tests
4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * Copyright 2009 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdio.h>
24 #include <windows.h>
25 #include <commctrl.h>
27 #include "wine/test.h"
28 #include "v6util.h"
29 #include "msg.h"
31 #define PARENT_SEQ_INDEX 0
32 #define PARENT_FULL_SEQ_INDEX 1
33 #define LISTVIEW_SEQ_INDEX 2
34 #define EDITBOX_SEQ_INDEX 3
35 #define NUM_MSG_SEQUENCES 4
37 #define LISTVIEW_ID 0
38 #define HEADER_ID 1
40 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
41 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
42 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
44 static const WCHAR testparentclassW[] =
45 {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
47 HWND hwndparent, hwndparentW;
48 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
49 BOOL blockEdit;
50 /* dumps LVN_ITEMCHANGED message data */
51 static BOOL g_dump_itemchanged;
52 /* format reported to control:
53 -1 falls to defproc, anything else returned */
54 INT notifyFormat;
55 /* indicates we're running < 5.80 version */
56 BOOL g_is_below_5;
58 static HWND subclass_editbox(HWND hwndListview);
60 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
62 static const struct message create_ownerdrawfixed_parent_seq[] = {
63 { WM_NOTIFYFORMAT, sent },
64 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
65 { WM_MEASUREITEM, sent },
66 { WM_PARENTNOTIFY, sent },
67 { 0 }
70 static const struct message redraw_listview_seq[] = {
71 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
72 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
73 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
74 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
75 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
76 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
77 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
78 { 0 }
81 static const struct message listview_icon_spacing_seq[] = {
82 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
83 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
84 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
85 { 0 }
88 static const struct message listview_color_seq[] = {
89 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
90 { LVM_GETBKCOLOR, sent },
91 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
92 { LVM_GETTEXTCOLOR, sent },
93 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
94 { LVM_GETTEXTBKCOLOR, sent },
96 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
97 { LVM_GETBKCOLOR, sent },
98 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
99 { LVM_GETTEXTCOLOR, sent },
100 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
101 { LVM_GETTEXTBKCOLOR, sent },
103 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
104 { LVM_GETBKCOLOR, sent },
105 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
106 { LVM_GETTEXTCOLOR, sent },
107 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
108 { LVM_GETTEXTBKCOLOR, sent },
110 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
111 { LVM_GETBKCOLOR, sent },
112 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
113 { LVM_GETTEXTCOLOR, sent },
114 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
115 { LVM_GETTEXTBKCOLOR, sent },
116 { 0 }
119 static const struct message listview_item_count_seq[] = {
120 { LVM_GETITEMCOUNT, sent },
121 { LVM_INSERTITEM, sent },
122 { LVM_INSERTITEM, sent },
123 { LVM_INSERTITEM, sent },
124 { LVM_GETITEMCOUNT, sent },
125 { LVM_DELETEITEM, sent|wparam, 2 },
126 { WM_NCPAINT, sent|optional },
127 { WM_ERASEBKGND, sent|optional },
128 { LVM_GETITEMCOUNT, sent },
129 { LVM_DELETEALLITEMS, sent },
130 { LVM_GETITEMCOUNT, sent },
131 { LVM_INSERTITEM, sent },
132 { LVM_INSERTITEM, sent },
133 { LVM_GETITEMCOUNT, sent },
134 { LVM_INSERTITEM, sent },
135 { LVM_GETITEMCOUNT, sent },
136 { 0 }
139 static const struct message listview_itempos_seq[] = {
140 { LVM_INSERTITEM, sent },
141 { LVM_INSERTITEM, sent },
142 { LVM_INSERTITEM, sent },
143 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
144 { WM_NCPAINT, sent|optional },
145 { WM_ERASEBKGND, sent|optional },
146 { LVM_GETITEMPOSITION, sent|wparam, 1 },
147 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
148 { LVM_GETITEMPOSITION, sent|wparam, 2 },
149 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
150 { LVM_GETITEMPOSITION, sent|wparam, 0 },
151 { 0 }
154 static const struct message listview_ownerdata_switchto_seq[] = {
155 { WM_STYLECHANGING, sent },
156 { WM_STYLECHANGED, sent },
157 { 0 }
160 static const struct message listview_getorderarray_seq[] = {
161 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
162 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
163 { 0 }
166 static const struct message empty_seq[] = {
167 { 0 }
170 static const struct message forward_erasebkgnd_parent_seq[] = {
171 { WM_ERASEBKGND, sent },
172 { 0 }
175 static const struct message ownderdata_select_focus_parent_seq[] = {
176 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
177 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
178 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
179 { 0 }
182 static const struct message ownerdata_setstate_all_parent_seq[] = {
183 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
184 { 0 }
187 static const struct message ownerdata_defocus_all_parent_seq[] = {
188 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
189 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
190 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
191 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
192 { 0 }
195 static const struct message ownerdata_deselect_all_parent_seq[] = {
196 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
197 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
198 { 0 }
201 static const struct message select_all_parent_seq[] = {
202 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
203 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
205 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
206 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
208 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
209 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
211 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
212 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
214 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
215 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
216 { 0 }
219 static const struct message textcallback_set_again_parent_seq[] = {
220 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
221 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
222 { 0 }
225 static const struct message single_getdispinfo_parent_seq[] = {
226 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
227 { 0 }
230 static const struct message getitemposition_seq1[] = {
231 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
232 { 0 }
235 static const struct message getitemposition_seq2[] = {
236 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
237 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
238 { 0 }
241 static const struct message editbox_create_pos[] = {
242 /* sequence sent after LVN_BEGINLABELEDIT */
243 /* next two are 4.7x specific */
244 { WM_WINDOWPOSCHANGING, sent },
245 { WM_WINDOWPOSCHANGED, sent|optional },
247 { WM_WINDOWPOSCHANGING, sent|optional },
248 { WM_NCCALCSIZE, sent },
249 { WM_WINDOWPOSCHANGED, sent },
250 { WM_MOVE, sent|defwinproc },
251 { WM_SIZE, sent|defwinproc },
252 /* the rest is todo, skipped in 4.7x */
253 { WM_WINDOWPOSCHANGING, sent|optional },
254 { WM_WINDOWPOSCHANGED, sent|optional },
255 { 0 }
258 static const struct message scroll_parent_seq[] = {
259 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
260 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
261 { 0 }
264 static const struct message setredraw_seq[] = {
265 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
266 { 0 }
269 static const struct message lvs_ex_transparentbkgnd_seq[] = {
270 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
271 { 0 }
274 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
276 static LONG defwndproc_counter = 0;
277 LRESULT ret;
278 struct message msg;
280 msg.message = message;
281 msg.flags = sent|wparam|lparam;
282 if (defwndproc_counter) msg.flags |= defwinproc;
283 msg.wParam = wParam;
284 msg.lParam = lParam;
285 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
287 /* log system messages, except for painting */
288 if (message < WM_USER &&
289 message != WM_PAINT &&
290 message != WM_ERASEBKGND &&
291 message != WM_NCPAINT &&
292 message != WM_NCHITTEST &&
293 message != WM_GETTEXT &&
294 message != WM_GETICON &&
295 message != WM_DEVICECHANGE)
297 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
299 add_message(sequences, PARENT_SEQ_INDEX, &msg);
301 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
303 switch (message)
305 case WM_NOTIFY:
307 switch (((NMHDR*)lParam)->code)
309 case LVN_BEGINLABELEDIT:
310 /* subclass edit box */
311 if (!blockEdit)
312 subclass_editbox(((NMHDR*)lParam)->hwndFrom);
314 return blockEdit;
316 case LVN_ENDLABELEDIT:
317 /* always accept new item text */
318 return TRUE;
319 case LVN_BEGINSCROLL:
320 case LVN_ENDSCROLL:
322 NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
324 trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
325 "BEGIN" : "END", pScroll->dx, pScroll->dy);
327 break;
328 case LVN_ITEMCHANGED:
329 if (g_dump_itemchanged)
331 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
332 trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
333 nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
335 break;
337 break;
339 case WM_NOTIFYFORMAT:
341 /* force to return format */
342 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
343 break;
347 defwndproc_counter++;
348 ret = DefWindowProcA(hwnd, message, wParam, lParam);
349 defwndproc_counter--;
351 return ret;
354 static BOOL register_parent_wnd_class(BOOL Unicode)
356 WNDCLASSA clsA;
357 WNDCLASSW clsW;
359 if (Unicode)
361 clsW.style = 0;
362 clsW.lpfnWndProc = parent_wnd_proc;
363 clsW.cbClsExtra = 0;
364 clsW.cbWndExtra = 0;
365 clsW.hInstance = GetModuleHandleW(NULL);
366 clsW.hIcon = 0;
367 clsW.hCursor = LoadCursorA(0, IDC_ARROW);
368 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
369 clsW.lpszMenuName = NULL;
370 clsW.lpszClassName = testparentclassW;
372 else
374 clsA.style = 0;
375 clsA.lpfnWndProc = parent_wnd_proc;
376 clsA.cbClsExtra = 0;
377 clsA.cbWndExtra = 0;
378 clsA.hInstance = GetModuleHandleA(NULL);
379 clsA.hIcon = 0;
380 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
381 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
382 clsA.lpszMenuName = NULL;
383 clsA.lpszClassName = "Listview test parent class";
386 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
389 static HWND create_parent_window(BOOL Unicode)
391 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W'};
392 HWND hwnd;
394 if (!register_parent_wnd_class(Unicode))
395 return NULL;
397 blockEdit = FALSE;
398 notifyFormat = -1;
400 if (Unicode)
401 hwnd = CreateWindowExW(0, testparentclassW, nameW,
402 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
403 WS_MAXIMIZEBOX | WS_VISIBLE,
404 0, 0, 100, 100,
405 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
406 else
407 hwnd = CreateWindowExA(0, "Listview test parent class",
408 "Listview test parent window",
409 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
410 WS_MAXIMIZEBOX | WS_VISIBLE,
411 0, 0, 100, 100,
412 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
413 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
414 return hwnd;
417 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
419 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
420 static LONG defwndproc_counter = 0;
421 LRESULT ret;
422 struct message msg;
424 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
426 /* some debug output for style changing */
427 if ((message == WM_STYLECHANGING ||
428 message == WM_STYLECHANGED) && lParam)
430 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
431 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
434 msg.message = message;
435 msg.flags = sent|wparam|lparam;
436 if (defwndproc_counter) msg.flags |= defwinproc;
437 msg.wParam = wParam;
438 msg.lParam = lParam;
439 msg.id = LISTVIEW_ID;
440 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
442 defwndproc_counter++;
443 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
444 defwndproc_counter--;
445 return ret;
448 static HWND create_listview_control(DWORD style)
450 WNDPROC oldproc;
451 HWND hwnd;
452 RECT rect;
454 GetClientRect(hwndparent, &rect);
455 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
456 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style,
457 0, 0, rect.right, rect.bottom,
458 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
459 ok(hwnd != NULL, "gle=%d\n", GetLastError());
461 if (!hwnd) return NULL;
463 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
464 (LONG_PTR)listview_subclass_proc);
465 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
467 return hwnd;
470 /* unicode listview window with specified parent */
471 static HWND create_listview_controlW(DWORD style, HWND parent)
473 WNDPROC oldproc;
474 HWND hwnd;
475 RECT rect;
476 static const WCHAR nameW[] = {'f','o','o',0};
478 GetClientRect(parent, &rect);
479 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
480 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style,
481 0, 0, rect.right, rect.bottom,
482 parent, NULL, GetModuleHandleW(NULL), NULL);
483 ok(hwnd != NULL, "gle=%d\n", GetLastError());
485 if (!hwnd) return NULL;
487 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
488 (LONG_PTR)listview_subclass_proc);
489 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
491 return hwnd;
494 static HWND create_custom_listview_control(DWORD style)
496 WNDPROC oldproc;
497 HWND hwnd;
498 RECT rect;
500 GetClientRect(hwndparent, &rect);
501 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
502 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
503 0, 0, rect.right, rect.bottom,
504 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
505 ok(hwnd != NULL, "gle=%d\n", GetLastError());
507 if (!hwnd) return NULL;
509 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
510 (LONG_PTR)listview_subclass_proc);
511 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
513 return hwnd;
516 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
518 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
519 static LONG defwndproc_counter = 0;
520 LRESULT ret;
521 struct message msg;
523 trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
525 msg.message = message;
526 msg.flags = sent|wparam|lparam;
527 if (defwndproc_counter) msg.flags |= defwinproc;
528 msg.wParam = wParam;
529 msg.lParam = lParam;
530 msg.id = HEADER_ID;
531 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
533 defwndproc_counter++;
534 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
535 defwndproc_counter--;
536 return ret;
539 static HWND subclass_header(HWND hwndListview)
541 WNDPROC oldproc;
542 HWND hwnd;
544 hwnd = ListView_GetHeader(hwndListview);
545 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
546 (LONG_PTR)header_subclass_proc);
547 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
549 return hwnd;
552 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
554 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
555 static LONG defwndproc_counter = 0;
556 LRESULT ret;
557 struct message msg;
559 msg.message = message;
560 msg.flags = sent|wparam|lparam;
561 if (defwndproc_counter) msg.flags |= defwinproc;
562 msg.wParam = wParam;
563 msg.lParam = lParam;
565 /* all we need is sizing */
566 if (message == WM_WINDOWPOSCHANGING ||
567 message == WM_NCCALCSIZE ||
568 message == WM_WINDOWPOSCHANGED ||
569 message == WM_MOVE ||
570 message == WM_SIZE)
572 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
575 defwndproc_counter++;
576 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
577 defwndproc_counter--;
578 return ret;
581 static HWND subclass_editbox(HWND hwndListview)
583 WNDPROC oldproc;
584 HWND hwnd;
586 hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0);
587 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
588 (LONG_PTR)editbox_subclass_proc);
589 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
591 return hwnd;
594 /* Performs a single LVM_HITTEST test */
595 static void test_lvm_hittest(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
596 BOOL todo_item, BOOL todo_flags, int line)
598 LVHITTESTINFO lpht;
599 DWORD ret;
601 lpht.pt.x = x;
602 lpht.pt.y = y;
603 lpht.iSubItem = 10;
605 trace("hittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
606 ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
608 if (todo_item)
610 todo_wine
612 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
613 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
614 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
617 else
619 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
620 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
621 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
624 if (todo_flags)
626 todo_wine
627 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
629 else if (broken_flags)
630 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
631 "Expected flags %x, got %x\n", flags, lpht.flags);
632 else
633 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
636 /* Performs a single LVM_SUBITEMHITTEST test */
637 static void test_lvm_subitemhittest(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
638 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
640 LVHITTESTINFO lpht;
641 DWORD ret;
643 lpht.pt.x = x;
644 lpht.pt.y = y;
646 trace("subhittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
647 ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
649 if (todo_item)
651 todo_wine
653 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
654 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
657 else
659 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
660 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
663 if (todo_subitem)
665 todo_wine
666 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
668 else
669 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
671 if (todo_flags)
673 todo_wine
674 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
676 else
677 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
680 static void test_images(void)
682 HWND hwnd;
683 DWORD r;
684 LVITEM item;
685 HIMAGELIST himl;
686 HBITMAP hbmp;
687 RECT r1, r2;
688 static CHAR hello[] = "hello";
690 himl = ImageList_Create(40, 40, 0, 4, 4);
691 ok(himl != NULL, "failed to create imagelist\n");
693 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
694 ok(hbmp != NULL, "failed to create bitmap\n");
696 r = ImageList_Add(himl, hbmp, 0);
697 ok(r == 0, "should be zero\n");
699 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
700 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
701 ok(hwnd != NULL, "failed to create listview window\n");
703 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
704 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
706 ok(r == 0, "should return zero\n");
708 r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
709 ok(r == 0, "should return zero\n");
711 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
712 /* returns dimensions */
714 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
715 ok(r == 0, "should be zero items\n");
717 item.mask = LVIF_IMAGE | LVIF_TEXT;
718 item.iItem = 0;
719 item.iSubItem = 1;
720 item.iImage = 0;
721 item.pszText = 0;
722 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
723 ok(r == -1, "should fail\n");
725 item.iSubItem = 0;
726 item.pszText = hello;
727 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
728 ok(r == 0, "should not fail\n");
730 memset(&r1, 0, sizeof r1);
731 r1.left = LVIR_ICON;
732 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
734 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
735 ok(r == TRUE, "should not fail\n");
737 item.iSubItem = 0;
738 item.pszText = hello;
739 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
740 ok(r == 0, "should not fail\n");
742 memset(&r2, 0, sizeof r2);
743 r2.left = LVIR_ICON;
744 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
746 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
748 DestroyWindow(hwnd);
751 static void test_checkboxes(void)
753 HWND hwnd;
754 LVITEMA item;
755 DWORD r;
756 static CHAR text[] = "Text",
757 text2[] = "Text2",
758 text3[] = "Text3";
760 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
761 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
762 ok(hwnd != NULL, "failed to create listview window\n");
764 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
765 item.mask = LVIF_TEXT | LVIF_STATE;
766 item.stateMask = 0xffff;
767 item.state = 0xfccc;
768 item.iItem = 0;
769 item.iSubItem = 0;
770 item.pszText = text;
771 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
772 ok(r == 0, "ret %d\n", r);
774 item.iItem = 0;
775 item.mask = LVIF_STATE;
776 item.stateMask = 0xffff;
777 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
778 ok(item.state == 0xfccc, "state %x\n", item.state);
780 /* Don't set LVIF_STATE */
781 item.mask = LVIF_TEXT;
782 item.stateMask = 0xffff;
783 item.state = 0xfccc;
784 item.iItem = 1;
785 item.iSubItem = 0;
786 item.pszText = text;
787 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
788 ok(r == 1, "ret %d\n", r);
790 item.iItem = 1;
791 item.mask = LVIF_STATE;
792 item.stateMask = 0xffff;
793 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
794 ok(item.state == 0, "state %x\n", item.state);
796 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
797 ok(r == 0, "should return zero\n");
799 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
800 item.iItem = 0;
801 item.mask = LVIF_STATE;
802 item.stateMask = 0xffff;
803 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
804 if (item.state != 0x1ccc)
806 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
807 DestroyWindow(hwnd);
808 return;
811 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
812 item.iItem = 2;
813 item.mask = LVIF_TEXT;
814 item.state = 0;
815 item.pszText = text2;
816 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
817 ok(r == 2, "ret %d\n", r);
819 item.iItem = 2;
820 item.mask = LVIF_STATE;
821 item.stateMask = 0xffff;
822 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
823 ok(item.state == 0x1000, "state %x\n", item.state);
825 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
826 item.iItem = 3;
827 item.mask = LVIF_TEXT | LVIF_STATE;
828 item.stateMask = 0xffff;
829 item.state = 0x2aaa;
830 item.pszText = text3;
831 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
832 ok(r == 3, "ret %d\n", r);
834 item.iItem = 3;
835 item.mask = LVIF_STATE;
836 item.stateMask = 0xffff;
837 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
838 ok(item.state == 0x1aaa, "state %x\n", item.state);
840 /* Set an item's state to checked */
841 item.iItem = 3;
842 item.mask = LVIF_STATE;
843 item.stateMask = 0xf000;
844 item.state = 0x2000;
845 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
847 item.iItem = 3;
848 item.mask = LVIF_STATE;
849 item.stateMask = 0xffff;
850 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
851 ok(item.state == 0x2aaa, "state %x\n", item.state);
853 /* Check that only the bits we asked for are returned,
854 * and that all the others are set to zero
856 item.iItem = 3;
857 item.mask = LVIF_STATE;
858 item.stateMask = 0xf000;
859 item.state = 0xffff;
860 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
861 ok(item.state == 0x2000, "state %x\n", item.state);
863 /* Set the style again and check that doesn't change an item's state */
864 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
865 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
867 item.iItem = 3;
868 item.mask = LVIF_STATE;
869 item.stateMask = 0xffff;
870 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
871 ok(item.state == 0x2aaa, "state %x\n", item.state);
873 /* Unsetting the checkbox extended style doesn't change an item's state */
874 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
875 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
877 item.iItem = 3;
878 item.mask = LVIF_STATE;
879 item.stateMask = 0xffff;
880 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
881 ok(item.state == 0x2aaa, "state %x\n", item.state);
883 /* Now setting the style again will change an item's state */
884 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
885 ok(r == 0, "ret %x\n", r);
887 item.iItem = 3;
888 item.mask = LVIF_STATE;
889 item.stateMask = 0xffff;
890 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
891 ok(item.state == 0x1aaa, "state %x\n", item.state);
893 /* Toggle checkbox tests (bug 9934) */
894 memset (&item, 0xcc, sizeof(item));
895 item.mask = LVIF_STATE;
896 item.iItem = 3;
897 item.iSubItem = 0;
898 item.state = LVIS_FOCUSED;
899 item.stateMask = LVIS_FOCUSED;
900 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
901 expect(1, r);
903 item.iItem = 3;
904 item.mask = LVIF_STATE;
905 item.stateMask = 0xffff;
906 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
907 ok(item.state == 0x1aab, "state %x\n", item.state);
909 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
910 expect(0, r);
911 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
912 expect(0, r);
914 item.iItem = 3;
915 item.mask = LVIF_STATE;
916 item.stateMask = 0xffff;
917 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
918 ok(item.state == 0x2aab, "state %x\n", item.state);
920 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
921 expect(0, r);
922 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
923 expect(0, r);
925 item.iItem = 3;
926 item.mask = LVIF_STATE;
927 item.stateMask = 0xffff;
928 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
929 ok(item.state == 0x1aab, "state %x\n", item.state);
931 DestroyWindow(hwnd);
934 static void insert_column(HWND hwnd, int idx)
936 LVCOLUMN column;
937 DWORD rc;
939 memset(&column, 0xcc, sizeof(column));
940 column.mask = LVCF_SUBITEM;
941 column.iSubItem = idx;
943 rc = ListView_InsertColumn(hwnd, idx, &column);
944 expect(idx, rc);
947 static void insert_item(HWND hwnd, int idx)
949 static CHAR text[] = "foo";
951 LVITEMA item;
952 DWORD rc;
954 memset(&item, 0xcc, sizeof (item));
955 item.mask = LVIF_TEXT;
956 item.iItem = idx;
957 item.iSubItem = 0;
958 item.pszText = text;
960 rc = ListView_InsertItem(hwnd, &item);
961 expect(idx, rc);
964 static void test_items(void)
966 const LPARAM lparamTest = 0x42;
967 HWND hwnd;
968 LVITEMA item;
969 DWORD r;
970 static CHAR text[] = "Text";
972 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
973 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
974 ok(hwnd != NULL, "failed to create listview window\n");
977 * Test setting/getting item params
980 /* Set up two columns */
981 insert_column(hwnd, 0);
982 insert_column(hwnd, 1);
984 /* LVIS_SELECTED with zero stateMask */
985 /* set */
986 memset (&item, 0, sizeof (item));
987 item.mask = LVIF_STATE;
988 item.state = LVIS_SELECTED;
989 item.stateMask = 0;
990 item.iItem = 0;
991 item.iSubItem = 0;
992 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
993 ok(r == 0, "ret %d\n", r);
994 /* get */
995 memset (&item, 0xcc, sizeof (item));
996 item.mask = LVIF_STATE;
997 item.stateMask = LVIS_SELECTED;
998 item.state = 0;
999 item.iItem = 0;
1000 item.iSubItem = 0;
1001 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1002 ok(r != 0, "ret %d\n", r);
1003 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1004 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1006 /* LVIS_SELECTED with zero stateMask */
1007 /* set */
1008 memset (&item, 0, sizeof (item));
1009 item.mask = LVIF_STATE;
1010 item.state = LVIS_FOCUSED;
1011 item.stateMask = 0;
1012 item.iItem = 0;
1013 item.iSubItem = 0;
1014 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1015 ok(r == 0, "ret %d\n", r);
1016 /* get */
1017 memset (&item, 0xcc, sizeof (item));
1018 item.mask = LVIF_STATE;
1019 item.stateMask = LVIS_FOCUSED;
1020 item.state = 0;
1021 item.iItem = 0;
1022 item.iSubItem = 0;
1023 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1024 ok(r != 0, "ret %d\n", r);
1025 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1026 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1028 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1029 /* set */
1030 memset (&item, 0, sizeof (item));
1031 item.mask = LVIF_STATE;
1032 item.state = LVIS_CUT;
1033 item.stateMask = LVIS_FOCUSED;
1034 item.iItem = 0;
1035 item.iSubItem = 0;
1036 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1037 ok(r == 0, "ret %d\n", r);
1038 /* get */
1039 memset (&item, 0xcc, sizeof (item));
1040 item.mask = LVIF_STATE;
1041 item.stateMask = LVIS_CUT;
1042 item.state = 0;
1043 item.iItem = 0;
1044 item.iSubItem = 0;
1045 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1046 ok(r != 0, "ret %d\n", r);
1047 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1048 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1050 /* Insert an item with just a param */
1051 memset (&item, 0xcc, sizeof (item));
1052 item.mask = LVIF_PARAM;
1053 item.iItem = 0;
1054 item.iSubItem = 0;
1055 item.lParam = lparamTest;
1056 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1057 ok(r == 0, "ret %d\n", r);
1059 /* Test getting of the param */
1060 memset (&item, 0xcc, sizeof (item));
1061 item.mask = LVIF_PARAM;
1062 item.iItem = 0;
1063 item.iSubItem = 0;
1064 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1065 ok(r != 0, "ret %d\n", r);
1066 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1068 /* Set up a subitem */
1069 memset (&item, 0xcc, sizeof (item));
1070 item.mask = LVIF_TEXT;
1071 item.iItem = 0;
1072 item.iSubItem = 1;
1073 item.pszText = text;
1074 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1075 ok(r != 0, "ret %d\n", r);
1077 /* Query param from subitem: returns main item param */
1078 memset (&item, 0xcc, sizeof (item));
1079 item.mask = LVIF_PARAM;
1080 item.iItem = 0;
1081 item.iSubItem = 1;
1082 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1083 ok(r != 0, "ret %d\n", r);
1084 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1086 /* Set up param on first subitem: no effect */
1087 memset (&item, 0xcc, sizeof (item));
1088 item.mask = LVIF_PARAM;
1089 item.iItem = 0;
1090 item.iSubItem = 1;
1091 item.lParam = lparamTest+1;
1092 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1093 ok(r == 0, "ret %d\n", r);
1095 /* Query param from subitem again: should still return main item param */
1096 memset (&item, 0xcc, sizeof (item));
1097 item.mask = LVIF_PARAM;
1098 item.iItem = 0;
1099 item.iSubItem = 1;
1100 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1101 ok(r != 0, "ret %d\n", r);
1102 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1104 /**** Some tests of state highlighting ****/
1105 memset (&item, 0xcc, sizeof (item));
1106 item.mask = LVIF_STATE;
1107 item.iItem = 0;
1108 item.iSubItem = 0;
1109 item.state = LVIS_SELECTED;
1110 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1111 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1112 ok(r != 0, "ret %d\n", r);
1113 item.iSubItem = 1;
1114 item.state = LVIS_DROPHILITED;
1115 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1116 ok(r != 0, "ret %d\n", r);
1118 memset (&item, 0xcc, sizeof (item));
1119 item.mask = LVIF_STATE;
1120 item.iItem = 0;
1121 item.iSubItem = 0;
1122 item.stateMask = -1;
1123 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1124 ok(r != 0, "ret %d\n", r);
1125 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1126 item.iSubItem = 1;
1127 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1128 ok(r != 0, "ret %d\n", r);
1129 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1131 /* some notnull but meaningless masks */
1132 memset (&item, 0, sizeof(item));
1133 item.mask = LVIF_NORECOMPUTE;
1134 item.iItem = 0;
1135 item.iSubItem = 0;
1136 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1137 ok(r != 0, "ret %d\n", r);
1138 memset (&item, 0, sizeof(item));
1139 item.mask = LVIF_DI_SETITEM;
1140 item.iItem = 0;
1141 item.iSubItem = 0;
1142 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1143 ok(r != 0, "ret %d\n", r);
1145 /* set text to callback value already having it */
1146 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1147 expect(TRUE, r);
1148 memset (&item, 0, sizeof (item));
1149 item.mask = LVIF_TEXT;
1150 item.pszText = LPSTR_TEXTCALLBACK;
1151 item.iItem = 0;
1152 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1153 ok(r == 0, "ret %d\n", r);
1154 memset (&item, 0, sizeof (item));
1156 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1158 item.pszText = LPSTR_TEXTCALLBACK;
1159 r = SendMessage(hwnd, LVM_SETITEMTEXT, 0 , (LPARAM) &item);
1160 expect(TRUE, r);
1162 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1163 "check callback text comparison rule", FALSE);
1165 DestroyWindow(hwnd);
1168 static void test_columns(void)
1170 HWND hwnd, hwndheader;
1171 LVCOLUMN column;
1172 DWORD rc;
1173 INT order[2];
1175 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
1176 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1177 ok(hwnd != NULL, "failed to create listview window\n");
1179 /* Add a column with no mask */
1180 memset(&column, 0xcc, sizeof(column));
1181 column.mask = 0;
1182 rc = ListView_InsertColumn(hwnd, 0, &column);
1183 ok(rc==0, "Inserting column with no mask failed with %d\n", rc);
1185 /* Check its width */
1186 rc = ListView_GetColumnWidth(hwnd, 0);
1187 ok(rc==10 ||
1188 broken(rc==0), /* win9x */
1189 "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1191 DestroyWindow(hwnd);
1193 /* LVM_GETCOLUMNORDERARRAY */
1194 hwnd = create_listview_control(0);
1195 hwndheader = subclass_header(hwnd);
1197 memset(&column, 0, sizeof(column));
1198 column.mask = LVCF_WIDTH;
1199 column.cx = 100;
1200 rc = ListView_InsertColumn(hwnd, 0, &column);
1201 ok(rc == 0, "Inserting column failed with %d\n", rc);
1203 column.cx = 200;
1204 rc = ListView_InsertColumn(hwnd, 1, &column);
1205 ok(rc == 1, "Inserting column failed with %d\n", rc);
1207 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1209 rc = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1210 ok(rc != 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
1211 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1212 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1214 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1216 DestroyWindow(hwnd);
1218 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1219 static WNDPROC listviewWndProc;
1220 static HIMAGELIST test_create_imagelist;
1222 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1224 LRESULT ret;
1226 if (uMsg == WM_CREATE)
1228 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
1229 lpcs->style |= LVS_REPORT;
1231 ret = CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
1232 if (uMsg == WM_CREATE) SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1233 return ret;
1236 static void test_create(void)
1238 HWND hList;
1239 HWND hHeader;
1240 LONG_PTR ret;
1241 LONG r;
1242 LVCOLUMNA col;
1243 RECT rect;
1244 WNDCLASSEX cls;
1245 cls.cbSize = sizeof(WNDCLASSEX);
1246 ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1247 listviewWndProc = cls.lpfnWndProc;
1248 cls.lpfnWndProc = create_test_wndproc;
1249 cls.lpszClassName = "MyListView32";
1250 ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
1252 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1253 hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1254 ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1255 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1257 if (!IsWindow(hHeader))
1259 /* version 4.0 */
1260 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1261 DestroyWindow(hList);
1262 return;
1265 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1266 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1267 DestroyWindow(hList);
1269 /* header isn't created on LVS_ICON and LVS_LIST styles */
1270 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1271 GetModuleHandle(NULL), 0);
1272 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1273 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1274 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1275 /* insert column */
1276 memset(&col, 0, sizeof(LVCOLUMNA));
1277 col.mask = LVCF_WIDTH;
1278 col.cx = 100;
1279 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1280 ok(r == 0, "Expected 0 column's inserted\n");
1281 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1282 ok(IsWindow(hHeader), "Header should be created\n");
1283 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1284 DestroyWindow(hList);
1286 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1287 GetModuleHandle(NULL), 0);
1288 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1289 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1290 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1291 /* insert column */
1292 memset(&col, 0, sizeof(LVCOLUMNA));
1293 col.mask = LVCF_WIDTH;
1294 col.cx = 100;
1295 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1296 ok(r == 0, "Expected 0 column's inserted\n");
1297 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1298 ok(IsWindow(hHeader), "Header should be created\n");
1299 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1300 DestroyWindow(hList);
1302 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1303 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1304 GetModuleHandle(NULL), 0);
1305 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLongPtr(hList, GWL_STYLE) | LVS_REPORT);
1306 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1307 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1308 ok(IsWindow(hHeader), "Header should be created\n");
1309 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLong(hList, GWL_STYLE) & ~LVS_REPORT);
1310 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1311 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1312 ok(IsWindow(hHeader), "Header should be created\n");
1313 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1314 DestroyWindow(hList);
1316 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1317 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1318 GetModuleHandle(NULL), 0);
1319 ret = SetWindowLongPtr(hList, GWL_STYLE,
1320 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1321 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1322 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1323 ok(IsWindow(hHeader), "Header should be created\n");
1324 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1325 ret = SetWindowLongPtr(hList, GWL_STYLE,
1326 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1327 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1328 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1329 ok(IsWindow(hHeader), "Header should be created\n");
1330 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1331 DestroyWindow(hList);
1333 /* LVS_REPORT without WS_VISIBLE */
1334 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1335 GetModuleHandle(NULL), 0);
1336 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1337 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1338 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1339 /* insert column */
1340 memset(&col, 0, sizeof(LVCOLUMNA));
1341 col.mask = LVCF_WIDTH;
1342 col.cx = 100;
1343 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1344 ok(r == 0, "Expected 0 column's inserted\n");
1345 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1346 ok(IsWindow(hHeader), "Header should be created\n");
1347 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1348 DestroyWindow(hList);
1350 /* LVS_REPORT without WS_VISIBLE, try to show it */
1351 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1352 GetModuleHandle(NULL), 0);
1353 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1354 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1355 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1356 ShowWindow(hList, SW_SHOW);
1357 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1358 ok(IsWindow(hHeader), "Header should be created\n");
1359 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1360 DestroyWindow(hList);
1362 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1363 hList = CreateWindow("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1364 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1365 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1366 ok(IsWindow(hHeader), "Header should be created\n");
1367 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1368 /* HDS_DRAGDROP set by default */
1369 ok(GetWindowLongPtr(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1370 DestroyWindow(hList);
1372 /* setting LVS_EX_HEADERDRAGDROP creates header */
1373 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1374 GetModuleHandle(NULL), 0);
1375 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1376 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1377 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1378 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1379 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1380 ok(IsWindow(hHeader) ||
1381 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1382 "Header should be created\n");
1383 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1384 DestroyWindow(hList);
1386 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1387 hList = create_custom_listview_control(0);
1388 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1389 r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1390 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1391 DestroyWindow(hList);
1393 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1394 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1395 GetModuleHandle(NULL), 0);
1396 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1397 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1399 rect.left = LVIR_BOUNDS;
1400 rect.top = 1;
1401 rect.right = rect.bottom = -10;
1402 r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1403 ok(r != 0, "Expected not-null LRESULT\n");
1405 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1406 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1407 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1409 DestroyWindow(hList);
1411 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1412 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1413 hList = create_listview_control(LVS_OWNERDRAWFIXED);
1414 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1415 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1416 DestroyWindow(hList);
1419 static void test_redraw(void)
1421 HWND hwnd, hwndheader;
1422 HDC hdc;
1423 BOOL res;
1424 DWORD r;
1426 hwnd = create_listview_control(0);
1427 hwndheader = subclass_header(hwnd);
1429 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1431 trace("invalidate & update\n");
1432 InvalidateRect(hwnd, NULL, TRUE);
1433 UpdateWindow(hwnd);
1434 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1436 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1438 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1439 /* 1. Without backbuffer */
1440 res = ListView_SetBkColor(hwnd, CLR_NONE);
1441 expect(TRUE, res);
1443 hdc = GetWindowDC(hwndparent);
1445 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1446 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1447 ok(r != 0, "Expected not zero result\n");
1448 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1449 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1451 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1452 expect(TRUE, res);
1454 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1455 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1456 ok(r != 0, "Expected not zero result\n");
1457 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1458 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1460 /* 2. With backbuffer */
1461 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1462 LVS_EX_DOUBLEBUFFER);
1463 res = ListView_SetBkColor(hwnd, CLR_NONE);
1464 expect(TRUE, res);
1466 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1467 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1468 ok(r != 0, "Expected not zero result\n");
1469 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1470 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1472 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1473 expect(TRUE, res);
1475 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1476 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1477 todo_wine ok(r != 0, "Expected not zero result\n");
1478 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1479 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1481 ReleaseDC(hwndparent, hdc);
1483 DestroyWindow(hwnd);
1486 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1488 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1490 if(msg == WM_NOTIFY) {
1491 NMHDR *nmhdr = (PVOID)lp;
1492 if(nmhdr->code == NM_CUSTOMDRAW) {
1493 NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
1494 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
1495 switch(nmlvcd->nmcd.dwDrawStage) {
1496 case CDDS_PREPAINT:
1497 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1498 return CDRF_NOTIFYITEMDRAW;
1499 case CDDS_ITEMPREPAINT:
1500 nmlvcd->clrTextBk = CLR_DEFAULT;
1501 return CDRF_NOTIFYSUBITEMDRAW;
1502 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1503 clr = GetBkColor(nmlvcd->nmcd.hdc);
1504 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1505 return CDRF_NOTIFYPOSTPAINT;
1506 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1507 clr = GetBkColor(nmlvcd->nmcd.hdc);
1508 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1509 return CDRF_DODEFAULT;
1511 return CDRF_DODEFAULT;
1515 return DefWindowProcA(hwnd, msg, wp, lp);
1518 static void test_customdraw(void)
1520 HWND hwnd;
1521 WNDPROC oldwndproc;
1523 hwnd = create_listview_control(0);
1525 insert_column(hwnd, 0);
1526 insert_column(hwnd, 1);
1527 insert_item(hwnd, 0);
1529 oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
1530 (LONG_PTR)cd_wndproc);
1532 InvalidateRect(hwnd, NULL, TRUE);
1533 UpdateWindow(hwnd);
1535 SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1537 DestroyWindow(hwnd);
1540 static void test_icon_spacing(void)
1542 /* LVM_SETICONSPACING */
1543 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1545 HWND hwnd;
1546 WORD w, h;
1547 DWORD r;
1549 hwnd = create_custom_listview_control(LVS_ICON);
1550 ok(hwnd != NULL, "failed to create a listview window\n");
1552 r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY);
1553 expect(NFR_ANSI, r);
1555 /* reset the icon spacing to defaults */
1556 SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1558 /* now we can request what the defaults are */
1559 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1560 w = LOWORD(r);
1561 h = HIWORD(r);
1563 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1565 trace("test icon spacing\n");
1567 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1568 ok(r == MAKELONG(w, h) ||
1569 broken(r == MAKELONG(w, w)), /* win98 */
1570 "Expected %d, got %d\n", MAKELONG(w, h), r);
1572 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1573 if (r == 0)
1575 /* version 4.0 */
1576 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1577 DestroyWindow(hwnd);
1578 return;
1580 expect(MAKELONG(20,30), r);
1582 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1583 expect(MAKELONG(25,35), r);
1585 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1587 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1588 DestroyWindow(hwnd);
1591 static void test_color(void)
1593 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1595 HWND hwnd;
1596 DWORD r;
1597 int i;
1599 COLORREF color;
1600 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1602 hwnd = create_listview_control(0);
1603 ok(hwnd != NULL, "failed to create a listview window\n");
1605 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1607 trace("test color seq\n");
1608 for (i = 0; i < 4; i++)
1610 color = colors[i];
1612 r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
1613 expect(TRUE, r);
1614 r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color);
1615 expect(color, r);
1617 r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
1618 expect (TRUE, r);
1619 r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color);
1620 expect(color, r);
1622 r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1623 expect(TRUE, r);
1624 r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color);
1625 expect(color, r);
1628 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1630 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1631 DestroyWindow(hwnd);
1634 static void test_item_count(void)
1636 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1638 HWND hwnd;
1639 DWORD r;
1640 HDC hdc;
1641 HFONT hOldFont;
1642 TEXTMETRICA tm;
1643 RECT rect;
1644 INT height;
1646 LVITEM item0;
1647 LVITEM item1;
1648 LVITEM item2;
1649 static CHAR item0text[] = "item0";
1650 static CHAR item1text[] = "item1";
1651 static CHAR item2text[] = "item2";
1653 hwnd = create_listview_control(0);
1654 ok(hwnd != NULL, "failed to create a listview window\n");
1656 /* resize in dpiaware manner to fit all 3 items added */
1657 hdc = GetDC(0);
1658 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
1659 GetTextMetricsA(hdc, &tm);
1660 /* 2 extra pixels for bounds and header border */
1661 height = tm.tmHeight + 2;
1662 SelectObject(hdc, hOldFont);
1663 ReleaseDC(0, hdc);
1665 GetWindowRect(hwnd, &rect);
1666 /* 3 items + 1 header + 1 to be sure */
1667 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
1669 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1671 trace("test item count\n");
1673 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1674 expect(0, r);
1676 /* [item0] */
1677 item0.mask = LVIF_TEXT;
1678 item0.iItem = 0;
1679 item0.iSubItem = 0;
1680 item0.pszText = item0text;
1681 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1682 expect(0, r);
1684 /* [item0, item1] */
1685 item1.mask = LVIF_TEXT;
1686 item1.iItem = 1;
1687 item1.iSubItem = 0;
1688 item1.pszText = item1text;
1689 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1690 expect(1, r);
1692 /* [item0, item1, item2] */
1693 item2.mask = LVIF_TEXT;
1694 item2.iItem = 2;
1695 item2.iSubItem = 0;
1696 item2.pszText = item2text;
1697 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1698 expect(2, r);
1700 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1701 expect(3, r);
1703 /* [item0, item1] */
1704 r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0);
1705 expect(TRUE, r);
1707 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1708 expect(2, r);
1710 /* [] */
1711 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1712 expect(TRUE, r);
1714 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1715 expect(0, r);
1717 /* [item0] */
1718 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1719 expect(0, r);
1721 /* [item0, item1] */
1722 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1723 expect(1, r);
1725 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1726 expect(2, r);
1728 /* [item0, item1, item2] */
1729 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1730 expect(2, r);
1732 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1733 expect(3, r);
1735 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
1737 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1738 DestroyWindow(hwnd);
1741 static void test_item_position(void)
1743 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1745 HWND hwnd;
1746 DWORD r;
1747 POINT position;
1749 LVITEM item0;
1750 LVITEM item1;
1751 LVITEM item2;
1752 static CHAR item0text[] = "item0";
1753 static CHAR item1text[] = "item1";
1754 static CHAR item2text[] = "item2";
1756 hwnd = create_custom_listview_control(LVS_ICON);
1757 ok(hwnd != NULL, "failed to create a listview window\n");
1759 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1761 trace("test item position\n");
1763 /* [item0] */
1764 item0.mask = LVIF_TEXT;
1765 item0.iItem = 0;
1766 item0.iSubItem = 0;
1767 item0.pszText = item0text;
1768 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1769 expect(0, r);
1771 /* [item0, item1] */
1772 item1.mask = LVIF_TEXT;
1773 item1.iItem = 1;
1774 item1.iSubItem = 0;
1775 item1.pszText = item1text;
1776 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1777 expect(1, r);
1779 /* [item0, item1, item2] */
1780 item2.mask = LVIF_TEXT;
1781 item2.iItem = 2;
1782 item2.iSubItem = 0;
1783 item2.pszText = item2text;
1784 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1785 expect(2, r);
1787 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
1788 expect(TRUE, r);
1789 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
1790 expect(TRUE, r);
1791 expect2(10, 5, position.x, position.y);
1793 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
1794 expect(TRUE, r);
1795 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
1796 expect(TRUE, r);
1797 expect2(0, 0, position.x, position.y);
1799 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
1800 expect(TRUE, r);
1801 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
1802 expect(TRUE, r);
1803 expect2(20, 20, position.x, position.y);
1805 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
1807 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1808 DestroyWindow(hwnd);
1811 static void test_getorigin(void)
1813 /* LVM_GETORIGIN */
1815 HWND hwnd;
1816 DWORD r;
1817 POINT position;
1819 position.x = position.y = 0;
1821 hwnd = create_custom_listview_control(LVS_ICON);
1822 ok(hwnd != NULL, "failed to create a listview window\n");
1823 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1824 trace("test get origin results\n");
1825 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1826 expect(TRUE, r);
1827 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1828 DestroyWindow(hwnd);
1830 hwnd = create_custom_listview_control(LVS_SMALLICON);
1831 ok(hwnd != NULL, "failed to create a listview window\n");
1832 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1833 trace("test get origin results\n");
1834 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1835 expect(TRUE, r);
1836 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1837 DestroyWindow(hwnd);
1839 hwnd = create_custom_listview_control(LVS_LIST);
1840 ok(hwnd != NULL, "failed to create a listview window\n");
1841 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1842 trace("test get origin results\n");
1843 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1844 expect(FALSE, r);
1845 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1846 DestroyWindow(hwnd);
1848 hwnd = create_custom_listview_control(LVS_REPORT);
1849 ok(hwnd != NULL, "failed to create a listview window\n");
1850 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1851 trace("test get origin results\n");
1852 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1853 expect(FALSE, r);
1854 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1855 DestroyWindow(hwnd);
1859 static void test_multiselect(void)
1861 typedef struct t_select_task
1863 const char *descr;
1864 int initPos;
1865 int loopVK;
1866 int count;
1867 int result;
1868 } select_task;
1870 HWND hwnd;
1871 DWORD r;
1872 int i,j,item_count,selected_count;
1873 static const int items=5;
1874 BYTE kstate[256];
1875 select_task task;
1876 LONG_PTR style;
1877 LVITEMA item;
1879 static struct t_select_task task_list[] = {
1880 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
1881 { "using VK_UP", -1, VK_UP, -1, -1 },
1882 { "using VK_END", 0, VK_END, 1, -1 },
1883 { "using VK_HOME", -1, VK_HOME, 1, -1 }
1887 hwnd = create_listview_control(0);
1889 for (i=0;i<items;i++) {
1890 insert_item(hwnd, 0);
1893 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1895 expect(items,item_count);
1897 for (i=0;i<4;i++) {
1898 task = task_list[i];
1900 /* deselect all items */
1901 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1902 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1904 /* set initial position */
1905 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
1906 ListView_SetItemState(hwnd,(task.initPos == -1 ? item_count -1 : task.initPos),LVIS_SELECTED ,LVIS_SELECTED);
1908 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1910 ok(selected_count == 1, "There should be only one selected item at the beginning (is %d)\n",selected_count);
1912 /* Set SHIFT key pressed */
1913 GetKeyboardState(kstate);
1914 kstate[VK_SHIFT]=0x80;
1915 SetKeyboardState(kstate);
1917 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
1918 r = SendMessage(hwnd, WM_KEYDOWN, task.loopVK, 0);
1919 expect(0,r);
1920 r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
1921 expect(0,r);
1924 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1926 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);
1928 /* Set SHIFT key released */
1929 GetKeyboardState(kstate);
1930 kstate[VK_SHIFT]=0x00;
1931 SetKeyboardState(kstate);
1933 DestroyWindow(hwnd);
1935 /* make multiple selection, then switch to LVS_SINGLESEL */
1936 hwnd = create_listview_control(0);
1937 for (i=0;i<items;i++) {
1938 insert_item(hwnd, 0);
1940 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1941 expect(items,item_count);
1943 /* try with NULL pointer */
1944 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)NULL);
1945 expect(FALSE, r);
1947 /* select all, check notifications */
1948 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1950 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1952 item.stateMask = LVIS_SELECTED;
1953 item.state = LVIS_SELECTED;
1954 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
1955 expect(TRUE, r);
1957 ok_sequence(sequences, PARENT_SEQ_INDEX, select_all_parent_seq,
1958 "select all notification", FALSE);
1960 /* deselect all items */
1961 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1962 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1963 for (i=0;i<3;i++) {
1964 ListView_SetItemState(hwnd, i, LVIS_SELECTED, LVIS_SELECTED);
1967 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1968 expect(3, r);
1969 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1970 expect(-1, r);
1972 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1973 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
1974 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
1975 /* check that style is accepted */
1976 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1977 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
1979 for (i=0;i<3;i++) {
1980 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
1981 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
1983 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1984 expect(3, r);
1985 SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1986 expect(3, r);
1988 /* select one more */
1989 ListView_SetItemState(hwnd, 3, LVIS_SELECTED, LVIS_SELECTED);
1991 for (i=0;i<3;i++) {
1992 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
1993 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
1995 r = ListView_GetItemState(hwnd, 3, LVIS_SELECTED);
1996 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
1998 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1999 expect(1, r);
2000 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2001 expect(-1, r);
2003 /* try to select all on LVS_SINGLESEL */
2004 memset(&item, 0, sizeof(item));
2005 item.stateMask = LVIS_SELECTED;
2006 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2007 expect(TRUE, r);
2008 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2010 item.stateMask = LVIS_SELECTED;
2011 item.state = LVIS_SELECTED;
2012 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2013 expect(FALSE, r);
2015 r = ListView_GetSelectedCount(hwnd);
2016 expect(0, r);
2017 r = ListView_GetSelectionMark(hwnd);
2018 expect(-1, r);
2020 /* try to deselect all on LVS_SINGLESEL */
2021 item.stateMask = LVIS_SELECTED;
2022 item.state = LVIS_SELECTED;
2023 r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2024 expect(TRUE, r);
2026 item.stateMask = LVIS_SELECTED;
2027 item.state = 0;
2028 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2029 expect(TRUE, r);
2030 r = ListView_GetSelectedCount(hwnd);
2031 expect(0, r);
2033 DestroyWindow(hwnd);
2036 static void test_subitem_rect(void)
2038 HWND hwnd;
2039 DWORD r;
2040 LVCOLUMN col;
2041 RECT rect;
2043 /* test LVM_GETSUBITEMRECT for header */
2044 hwnd = create_listview_control(0);
2045 ok(hwnd != NULL, "failed to create a listview window\n");
2046 /* add some columns */
2047 memset(&col, 0, sizeof(LVCOLUMN));
2048 col.mask = LVCF_WIDTH;
2049 col.cx = 100;
2050 r = -1;
2051 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
2052 expect(0, r);
2053 col.cx = 150;
2054 r = -1;
2055 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
2056 expect(1, r);
2057 col.cx = 200;
2058 r = -1;
2059 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
2060 expect(2, r);
2061 /* item = -1 means header, subitem index is 1 based */
2062 rect.left = LVIR_BOUNDS;
2063 rect.top = 0;
2064 rect.right = rect.bottom = 0;
2065 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2066 expect(0, r);
2068 rect.left = LVIR_BOUNDS;
2069 rect.top = 1;
2070 rect.right = rect.bottom = 0;
2071 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2073 ok(r != 0, "Expected not-null LRESULT\n");
2074 expect(100, rect.left);
2075 expect(250, rect.right);
2076 todo_wine
2077 expect(3, rect.top);
2079 rect.left = LVIR_BOUNDS;
2080 rect.top = 2;
2081 rect.right = rect.bottom = 0;
2082 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2084 ok(r != 0, "Expected not-null LRESULT\n");
2085 expect(250, rect.left);
2086 expect(450, rect.right);
2087 todo_wine
2088 expect(3, rect.top);
2090 /* item LVS_REPORT padding isn't applied to subitems */
2091 insert_item(hwnd, 0);
2093 rect.left = LVIR_BOUNDS;
2094 rect.top = 1;
2095 rect.right = rect.bottom = 0;
2096 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2097 ok(r != 0, "Expected not-null LRESULT\n");
2098 expect(100, rect.left);
2099 expect(250, rect.right);
2101 rect.left = LVIR_ICON;
2102 rect.top = 1;
2103 rect.right = rect.bottom = 0;
2104 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2105 ok(r != 0, "Expected not-null LRESULT\n");
2106 /* no icon attached - zero width rectangle, with no left padding */
2107 expect(100, rect.left);
2108 expect(100, rect.right);
2110 rect.left = LVIR_LABEL;
2111 rect.top = 1;
2112 rect.right = rect.bottom = 0;
2113 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2114 ok(r != 0, "Expected not-null LRESULT\n");
2115 /* same as full LVIR_BOUNDS */
2116 expect(100, rect.left);
2117 expect(250, rect.right);
2119 DestroyWindow(hwnd);
2121 /* try it for non LVS_REPORT style */
2122 hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2123 GetModuleHandle(NULL), 0);
2124 rect.left = LVIR_BOUNDS;
2125 rect.top = 1;
2126 rect.right = rect.bottom = -10;
2127 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2128 ok(r == 0, "Expected not-null LRESULT\n");
2129 /* rect is unchanged */
2130 expect(0, rect.left);
2131 expect(-10, rect.right);
2132 expect(1, rect.top);
2133 expect(-10, rect.bottom);
2134 DestroyWindow(hwnd);
2137 /* comparison callback for test_sorting */
2138 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2140 if (first == second) return 0;
2141 return (first > second ? 1 : -1);
2144 static void test_sorting(void)
2146 HWND hwnd;
2147 LVITEMA item = {0};
2148 DWORD r;
2149 LONG_PTR style;
2150 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2151 CHAR buff[10];
2153 hwnd = create_listview_control(0);
2154 ok(hwnd != NULL, "failed to create a listview window\n");
2156 /* insert some items */
2157 item.mask = LVIF_PARAM | LVIF_STATE;
2158 item.state = LVIS_SELECTED;
2159 item.iItem = 0;
2160 item.iSubItem = 0;
2161 item.lParam = 3;
2162 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2163 expect(0, r);
2165 item.mask = LVIF_PARAM;
2166 item.iItem = 1;
2167 item.iSubItem = 0;
2168 item.lParam = 2;
2169 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2170 expect(1, r);
2172 item.mask = LVIF_STATE | LVIF_PARAM;
2173 item.state = LVIS_SELECTED;
2174 item.iItem = 2;
2175 item.iSubItem = 0;
2176 item.lParam = 4;
2177 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2178 expect(2, r);
2180 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2181 expect(-1, r);
2183 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2184 expect(2, r);
2186 r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2187 expect(TRUE, r);
2189 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2190 expect(2, r);
2191 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2192 expect(-1, r);
2193 r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2194 expect(0, r);
2195 r = SendMessage(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2196 expect(LVIS_SELECTED, r);
2197 r = SendMessage(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2198 expect(LVIS_SELECTED, r);
2200 DestroyWindow(hwnd);
2202 /* switch to LVS_SORTASCENDING when some items added */
2203 hwnd = create_listview_control(0);
2204 ok(hwnd != NULL, "failed to create a listview window\n");
2206 item.mask = LVIF_TEXT;
2207 item.iItem = 0;
2208 item.iSubItem = 0;
2209 item.pszText = names[1];
2210 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2211 expect(0, r);
2213 item.mask = LVIF_TEXT;
2214 item.iItem = 1;
2215 item.iSubItem = 0;
2216 item.pszText = names[2];
2217 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2218 expect(1, r);
2220 item.mask = LVIF_TEXT;
2221 item.iItem = 2;
2222 item.iSubItem = 0;
2223 item.pszText = names[0];
2224 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2225 expect(2, r);
2227 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2228 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2229 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2230 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2232 /* no sorting performed when switched to LVS_SORTASCENDING */
2233 item.mask = LVIF_TEXT;
2234 item.iItem = 0;
2235 item.pszText = buff;
2236 item.cchTextMax = sizeof(buff);
2237 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2238 expect(TRUE, r);
2239 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2241 item.iItem = 1;
2242 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2243 expect(TRUE, r);
2244 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2246 item.iItem = 2;
2247 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2248 expect(TRUE, r);
2249 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2251 /* adding new item doesn't resort list */
2252 item.mask = LVIF_TEXT;
2253 item.iItem = 3;
2254 item.iSubItem = 0;
2255 item.pszText = names[3];
2256 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2257 expect(3, r);
2259 item.mask = LVIF_TEXT;
2260 item.iItem = 0;
2261 item.pszText = buff;
2262 item.cchTextMax = sizeof(buff);
2263 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2264 expect(TRUE, r);
2265 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2267 item.iItem = 1;
2268 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2269 expect(TRUE, r);
2270 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2272 item.iItem = 2;
2273 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2274 expect(TRUE, r);
2275 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2277 item.iItem = 3;
2278 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2279 expect(TRUE, r);
2280 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2282 /* corner case - item should be placed at first position */
2283 item.mask = LVIF_TEXT;
2284 item.iItem = 4;
2285 item.iSubItem = 0;
2286 item.pszText = names[4];
2287 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2288 expect(0, r);
2290 item.iItem = 0;
2291 item.pszText = buff;
2292 item.cchTextMax = sizeof(buff);
2293 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2294 expect(TRUE, r);
2295 ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2297 item.iItem = 1;
2298 item.pszText = buff;
2299 item.cchTextMax = sizeof(buff);
2300 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2301 expect(TRUE, r);
2302 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2304 item.iItem = 2;
2305 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2306 expect(TRUE, r);
2307 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2309 item.iItem = 3;
2310 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2311 expect(TRUE, r);
2312 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2314 item.iItem = 4;
2315 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2316 expect(TRUE, r);
2317 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2319 DestroyWindow(hwnd);
2322 static void test_ownerdata(void)
2324 HWND hwnd;
2325 LONG_PTR style, ret;
2326 DWORD res;
2327 LVITEMA item;
2329 /* it isn't possible to set LVS_OWNERDATA after creation */
2330 if (g_is_below_5)
2332 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2334 else
2336 hwnd = create_listview_control(0);
2337 ok(hwnd != NULL, "failed to create a listview window\n");
2338 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2339 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
2341 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2343 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2344 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2345 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2346 "try to switch to LVS_OWNERDATA seq", FALSE);
2348 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2349 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
2350 DestroyWindow(hwnd);
2353 /* try to set LVS_OWNERDATA after creation just having it */
2354 hwnd = create_listview_control(LVS_OWNERDATA);
2355 ok(hwnd != NULL, "failed to create a listview window\n");
2356 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2357 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2359 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2361 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2362 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2363 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2364 "try to switch to LVS_OWNERDATA seq", FALSE);
2365 DestroyWindow(hwnd);
2367 /* try to remove LVS_OWNERDATA after creation just having it */
2368 if (g_is_below_5)
2370 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2372 else
2374 hwnd = create_listview_control(LVS_OWNERDATA);
2375 ok(hwnd != NULL, "failed to create a listview window\n");
2376 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2377 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2379 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2381 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
2382 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2383 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2384 "try to switch to LVS_OWNERDATA seq", FALSE);
2385 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2386 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2387 DestroyWindow(hwnd);
2390 /* try select an item */
2391 hwnd = create_listview_control(LVS_OWNERDATA);
2392 ok(hwnd != NULL, "failed to create a listview window\n");
2393 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2394 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2395 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2396 expect(0, res);
2397 memset(&item, 0, sizeof(item));
2398 item.stateMask = LVIS_SELECTED;
2399 item.state = LVIS_SELECTED;
2400 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2401 expect(TRUE, res);
2402 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2403 expect(1, res);
2404 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2405 expect(1, res);
2406 DestroyWindow(hwnd);
2408 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
2409 hwnd = create_listview_control(LVS_OWNERDATA);
2410 ok(hwnd != NULL, "failed to create a listview window\n");
2411 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2412 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2413 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2414 expect(1, res);
2415 memset(&item, 0, sizeof(item));
2416 item.mask = LVIF_STATE;
2417 item.iItem = 0;
2418 item.stateMask = LVIS_SELECTED;
2419 item.state = LVIS_SELECTED;
2420 res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2421 expect(FALSE, res);
2422 DestroyWindow(hwnd);
2424 /* check notifications after focused/selected changed */
2425 hwnd = create_listview_control(LVS_OWNERDATA);
2426 ok(hwnd != NULL, "failed to create a listview window\n");
2427 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
2428 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2430 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2432 memset(&item, 0, sizeof(item));
2433 item.stateMask = LVIS_SELECTED;
2434 item.state = LVIS_SELECTED;
2435 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2436 expect(TRUE, res);
2438 ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
2439 "ownerdata select notification", TRUE);
2441 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2443 memset(&item, 0, sizeof(item));
2444 item.stateMask = LVIS_FOCUSED;
2445 item.state = LVIS_FOCUSED;
2446 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2447 expect(TRUE, res);
2449 ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
2450 "ownerdata focus notification", TRUE);
2452 /* select all, check notifications */
2453 item.stateMask = LVIS_SELECTED;
2454 item.state = 0;
2455 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2456 expect(TRUE, res);
2458 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2460 item.stateMask = LVIS_SELECTED;
2461 item.state = LVIS_SELECTED;
2463 g_dump_itemchanged = TRUE;
2464 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2465 expect(TRUE, res);
2466 g_dump_itemchanged = FALSE;
2468 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2469 "ownerdata select all notification", TRUE);
2471 /* select all again, note that all items are selected already */
2472 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2473 item.stateMask = LVIS_SELECTED;
2474 item.state = LVIS_SELECTED;
2475 g_dump_itemchanged = TRUE;
2476 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2477 expect(TRUE, res);
2478 g_dump_itemchanged = FALSE;
2479 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2480 "ownerdata select all notification", TRUE);
2481 /* deselect all */
2482 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2483 item.stateMask = LVIS_SELECTED;
2484 item.state = 0;
2485 g_dump_itemchanged = TRUE;
2486 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2487 expect(TRUE, res);
2488 g_dump_itemchanged = FALSE;
2489 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
2490 "ownerdata deselect all notification", TRUE);
2492 /* select one, then deselect all */
2493 item.stateMask = LVIS_SELECTED;
2494 item.state = LVIS_SELECTED;
2495 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2496 expect(TRUE, res);
2497 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2498 item.stateMask = LVIS_SELECTED;
2499 item.state = 0;
2500 g_dump_itemchanged = TRUE;
2501 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2502 expect(TRUE, res);
2503 g_dump_itemchanged = FALSE;
2504 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
2505 "ownerdata select all notification", TRUE);
2507 /* remove focused, try to focus all */
2508 item.stateMask = LVIS_FOCUSED;
2509 item.state = LVIS_FOCUSED;
2510 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2511 expect(TRUE, res);
2512 item.stateMask = LVIS_FOCUSED;
2513 item.state = 0;
2514 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2515 expect(TRUE, res);
2516 item.stateMask = LVIS_FOCUSED;
2517 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
2518 expect(0, res);
2519 /* setting all to focused returns failure value */
2520 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2521 item.stateMask = LVIS_FOCUSED;
2522 item.state = LVIS_FOCUSED;
2523 g_dump_itemchanged = TRUE;
2524 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2525 expect(FALSE, res);
2526 g_dump_itemchanged = FALSE;
2527 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2528 "ownerdata focus all notification", FALSE);
2529 /* focus single item, remove all */
2530 item.stateMask = LVIS_FOCUSED;
2531 item.state = LVIS_FOCUSED;
2532 res = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2533 expect(TRUE, res);
2534 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2535 item.stateMask = LVIS_FOCUSED;
2536 item.state = 0;
2537 g_dump_itemchanged = TRUE;
2538 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2539 expect(TRUE, res);
2540 g_dump_itemchanged = FALSE;
2541 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
2542 "ownerdata remove focus all notification", TRUE);
2543 /* set all cut */
2544 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2545 item.stateMask = LVIS_CUT;
2546 item.state = LVIS_CUT;
2547 g_dump_itemchanged = TRUE;
2548 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2549 expect(TRUE, res);
2550 g_dump_itemchanged = FALSE;
2551 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2552 "ownerdata cut all notification", TRUE);
2553 /* all marked cut, try again */
2554 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2555 item.stateMask = LVIS_CUT;
2556 item.state = LVIS_CUT;
2557 g_dump_itemchanged = TRUE;
2558 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2559 expect(TRUE, res);
2560 g_dump_itemchanged = FALSE;
2561 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2562 "ownerdata cut all notification #2", TRUE);
2564 DestroyWindow(hwnd);
2566 /* check notifications on LVM_GETITEM */
2567 /* zero callback mask */
2568 hwnd = create_listview_control(LVS_OWNERDATA);
2569 ok(hwnd != NULL, "failed to create a listview window\n");
2570 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2571 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2573 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2575 memset(&item, 0, sizeof(item));
2576 item.stateMask = LVIS_SELECTED;
2577 item.mask = LVIF_STATE;
2578 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2579 expect(TRUE, res);
2581 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2582 "ownerdata getitem selected state 1", FALSE);
2584 /* non zero callback mask but not we asking for */
2585 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
2586 expect(TRUE, res);
2588 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2590 memset(&item, 0, sizeof(item));
2591 item.stateMask = LVIS_SELECTED;
2592 item.mask = LVIF_STATE;
2593 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2594 expect(TRUE, res);
2596 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2597 "ownerdata getitem selected state 2", FALSE);
2599 /* LVIS_OVERLAYMASK callback mask, asking for index */
2600 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2602 memset(&item, 0, sizeof(item));
2603 item.stateMask = LVIS_OVERLAYMASK;
2604 item.mask = LVIF_STATE;
2605 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2606 expect(TRUE, res);
2608 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
2609 "ownerdata getitem selected state 2", FALSE);
2611 DestroyWindow(hwnd);
2613 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
2614 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING);
2615 ok(hwnd != NULL, "failed to create a listview window\n");
2616 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2617 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2618 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2619 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
2620 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2621 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
2622 DestroyWindow(hwnd);
2623 /* apparently it's allowed to switch these style on after creation */
2624 hwnd = create_listview_control(LVS_OWNERDATA);
2625 ok(hwnd != NULL, "failed to create a listview window\n");
2626 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2627 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2628 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2629 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2630 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2631 DestroyWindow(hwnd);
2633 hwnd = create_listview_control(LVS_OWNERDATA);
2634 ok(hwnd != NULL, "failed to create a listview window\n");
2635 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2636 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2637 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
2638 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2639 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
2640 DestroyWindow(hwnd);
2643 static void test_norecompute(void)
2645 static CHAR testA[] = "test";
2646 CHAR buff[10];
2647 LVITEMA item;
2648 HWND hwnd;
2649 DWORD res;
2651 /* self containing control */
2652 hwnd = create_listview_control(0);
2653 ok(hwnd != NULL, "failed to create a listview window\n");
2654 memset(&item, 0, sizeof(item));
2655 item.mask = LVIF_TEXT | LVIF_STATE;
2656 item.iItem = 0;
2657 item.stateMask = LVIS_SELECTED;
2658 item.state = LVIS_SELECTED;
2659 item.pszText = testA;
2660 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2661 expect(0, res);
2662 /* retrieve with LVIF_NORECOMPUTE */
2663 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2664 item.iItem = 0;
2665 item.pszText = buff;
2666 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2667 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2668 expect(TRUE, res);
2669 ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
2671 item.mask = LVIF_TEXT;
2672 item.iItem = 1;
2673 item.pszText = LPSTR_TEXTCALLBACK;
2674 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2675 expect(1, res);
2677 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2678 item.iItem = 1;
2679 item.pszText = buff;
2680 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2682 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2683 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2684 expect(TRUE, res);
2685 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2686 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2687 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
2689 DestroyWindow(hwnd);
2691 /* LVS_OWNERDATA */
2692 hwnd = create_listview_control(LVS_OWNERDATA);
2693 ok(hwnd != NULL, "failed to create a listview window\n");
2695 item.mask = LVIF_STATE;
2696 item.stateMask = LVIS_SELECTED;
2697 item.state = LVIS_SELECTED;
2698 item.iItem = 0;
2699 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2700 expect(0, res);
2702 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2703 item.iItem = 0;
2704 item.pszText = buff;
2705 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2706 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2707 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2708 expect(TRUE, res);
2709 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2710 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2711 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
2713 DestroyWindow(hwnd);
2716 static void test_nosortheader(void)
2718 HWND hwnd, header;
2719 LONG_PTR style;
2721 hwnd = create_listview_control(0);
2722 ok(hwnd != NULL, "failed to create a listview window\n");
2724 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
2725 ok(IsWindow(header), "header expected\n");
2727 style = GetWindowLongPtr(header, GWL_STYLE);
2728 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
2730 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2731 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
2732 /* HDS_BUTTONS retained */
2733 style = GetWindowLongPtr(header, GWL_STYLE);
2734 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
2736 DestroyWindow(hwnd);
2738 /* create with LVS_NOSORTHEADER */
2739 hwnd = create_listview_control(LVS_NOSORTHEADER);
2740 ok(hwnd != NULL, "failed to create a listview window\n");
2742 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
2743 ok(IsWindow(header), "header expected\n");
2745 style = GetWindowLongPtr(header, GWL_STYLE);
2746 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
2748 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2749 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
2750 /* not changed here */
2751 style = GetWindowLongPtr(header, GWL_STYLE);
2752 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
2754 DestroyWindow(hwnd);
2757 static void test_setredraw(void)
2759 HWND hwnd;
2760 DWORD_PTR style;
2761 DWORD ret;
2762 HDC hdc;
2763 RECT rect;
2765 hwnd = create_listview_control(LVS_OWNERDATA);
2766 ok(hwnd != NULL, "failed to create a listview window\n");
2768 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
2769 ListView seems to handle it internally without DefWinProc */
2771 /* default value first */
2772 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
2773 expect(0, ret);
2774 /* disable */
2775 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2776 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
2777 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2778 expect(0, ret);
2779 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2780 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
2781 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
2782 expect(0, ret);
2784 /* check update rect after redrawing */
2785 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2786 expect(0, ret);
2787 InvalidateRect(hwnd, NULL, FALSE);
2788 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
2789 rect.right = rect.bottom = 1;
2790 GetUpdateRect(hwnd, &rect, FALSE);
2791 expect(0, rect.right);
2792 expect(0, rect.bottom);
2794 /* WM_ERASEBKGND */
2795 hdc = GetWindowDC(hwndparent);
2796 ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
2797 expect(TRUE, ret);
2798 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2799 expect(0, ret);
2800 ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
2801 expect(TRUE, ret);
2802 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
2803 expect(0, ret);
2804 ReleaseDC(hwndparent, hdc);
2806 /* check notification messages to show that repainting is disabled */
2807 ret = SendMessage(hwnd, LVM_SETITEMCOUNT, 1, 0);
2808 expect(TRUE, ret);
2809 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2810 expect(0, ret);
2811 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2813 InvalidateRect(hwnd, NULL, TRUE);
2814 UpdateWindow(hwnd);
2815 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2816 "redraw after WM_SETREDRAW (FALSE)", FALSE);
2818 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
2819 expect(TRUE, ret);
2820 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2821 InvalidateRect(hwnd, NULL, TRUE);
2822 UpdateWindow(hwnd);
2823 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2824 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
2826 /* message isn't forwarded to header */
2827 subclass_header(hwnd);
2828 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2829 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2830 expect(0, ret);
2831 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
2832 "WM_SETREDRAW: not forwarded to header", FALSE);
2834 DestroyWindow(hwnd);
2837 static void test_hittest(void)
2839 HWND hwnd;
2840 DWORD r;
2841 RECT bounds;
2842 LVITEMA item;
2843 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
2844 POINT pos;
2845 INT x, y;
2846 HIMAGELIST himl, himl2;
2847 HBITMAP hbmp;
2849 hwnd = create_listview_control(0);
2850 ok(hwnd != NULL, "failed to create a listview window\n");
2852 /* LVS_REPORT with a single subitem (2 columns) */
2853 insert_column(hwnd, 0);
2854 insert_column(hwnd, 1);
2855 insert_item(hwnd, 0);
2857 item.iSubItem = 0;
2858 /* the only purpose of that line is to be as long as a half item rect */
2859 item.pszText = text;
2860 r = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
2861 expect(TRUE, r);
2863 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
2864 expect(TRUE, r);
2865 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
2866 expect(TRUE, r);
2868 memset(&bounds, 0, sizeof(bounds));
2869 bounds.left = LVIR_BOUNDS;
2870 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
2871 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
2872 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
2873 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
2874 expect(TRUE, r);
2876 /* LVS_EX_FULLROWSELECT not set, no icons attached */
2877 x = pos.x + 50; /* column half width */
2878 y = pos.y + (bounds.bottom - bounds.top) / 2;
2879 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE, __LINE__);
2880 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2881 x = pos.x + 150; /* outside column */
2882 y = pos.y + (bounds.bottom - bounds.top) / 2;
2883 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2884 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2885 y = (bounds.bottom - bounds.top) / 2;
2886 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2887 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2888 /* outside possible client rectangle (to right) */
2889 x = pos.x + 500;
2890 y = pos.y + (bounds.bottom - bounds.top) / 2;
2891 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2892 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2893 y = (bounds.bottom - bounds.top) / 2;
2894 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2895 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2896 /* subitem returned with -1 item too */
2897 x = pos.x + 150;
2898 y = -10;
2899 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2900 /* parent client area is 100x100 by default */
2901 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
2902 x = pos.x + 150; /* outside column */
2903 y = pos.y + (bounds.bottom - bounds.top) / 2;
2904 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE, __LINE__);
2905 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2906 y = (bounds.bottom - bounds.top) / 2;
2907 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE, __LINE__);
2908 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2909 /* the same with LVS_EX_FULLROWSELECT */
2910 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
2911 x = pos.x + 150; /* outside column */
2912 y = pos.y + (bounds.bottom - bounds.top) / 2;
2913 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE, __LINE__);
2914 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2915 y = (bounds.bottom - bounds.top) / 2;
2916 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2917 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
2918 x = pos.x + 150; /* outside column */
2919 y = pos.y + (bounds.bottom - bounds.top) / 2;
2920 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2921 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2922 y = (bounds.bottom - bounds.top) / 2;
2923 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2924 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2925 /* outside possible client rectangle (to right) */
2926 x = pos.x + 500;
2927 y = pos.y + (bounds.bottom - bounds.top) / 2;
2928 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2929 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2930 y = (bounds.bottom - bounds.top) / 2;
2931 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2932 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2933 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
2934 himl = ImageList_Create(16, 16, 0, 4, 4);
2935 ok(himl != NULL, "failed to create imagelist\n");
2936 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
2937 ok(hbmp != NULL, "failed to create bitmap\n");
2938 r = ImageList_Add(himl, hbmp, 0);
2939 ok(r == 0, "should be zero\n");
2940 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
2941 ok(hbmp != NULL, "failed to create bitmap\n");
2942 r = ImageList_Add(himl, hbmp, 0);
2943 ok(r == 1, "should be one\n");
2945 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
2946 ok(r == 0, "should return zero\n");
2948 item.mask = LVIF_IMAGE;
2949 item.iImage = 0;
2950 item.iItem = 0;
2951 item.iSubItem = 0;
2952 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2953 expect(TRUE, r);
2954 /* on state icon */
2955 x = pos.x + 8;
2956 y = pos.y + (bounds.bottom - bounds.top) / 2;
2957 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE, __LINE__);
2958 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2959 y = (bounds.bottom - bounds.top) / 2;
2960 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2962 /* state icons indices are 1 based, check with valid index */
2963 item.mask = LVIF_STATE;
2964 item.state = INDEXTOSTATEIMAGEMASK(1);
2965 item.stateMask = LVIS_STATEIMAGEMASK;
2966 item.iItem = 0;
2967 item.iSubItem = 0;
2968 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2969 expect(TRUE, r);
2970 /* on state icon */
2971 x = pos.x + 8;
2972 y = pos.y + (bounds.bottom - bounds.top) / 2;
2973 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE, __LINE__);
2974 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2975 y = (bounds.bottom - bounds.top) / 2;
2976 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2978 himl2 = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)NULL);
2979 ok(himl2 == himl, "should return handle\n");
2981 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
2982 ok(r == 0, "should return zero\n");
2983 /* on item icon */
2984 x = pos.x + 8;
2985 y = pos.y + (bounds.bottom - bounds.top) / 2;
2986 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE, __LINE__);
2987 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE, __LINE__);
2988 y = (bounds.bottom - bounds.top) / 2;
2989 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE, __LINE__);
2991 DestroyWindow(hwnd);
2994 static void test_getviewrect(void)
2996 HWND hwnd;
2997 DWORD r;
2998 RECT rect;
2999 LVITEMA item;
3001 hwnd = create_listview_control(0);
3002 ok(hwnd != NULL, "failed to create a listview window\n");
3004 /* empty */
3005 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3006 expect(TRUE, r);
3008 insert_column(hwnd, 0);
3009 insert_column(hwnd, 1);
3011 memset(&item, 0, sizeof(item));
3012 item.iItem = 0;
3013 item.iSubItem = 0;
3014 SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3016 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3017 expect(TRUE, r);
3018 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3019 expect(TRUE, r);
3021 rect.left = rect.right = rect.top = rect.bottom = -1;
3022 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3023 expect(TRUE, r);
3024 /* left is set to (2e31-1) - XP SP2 */
3025 expect(0, rect.right);
3026 expect(0, rect.top);
3027 expect(0, rect.bottom);
3029 /* switch to LVS_ICON */
3030 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~LVS_REPORT);
3032 rect.left = rect.right = rect.top = rect.bottom = -1;
3033 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3034 expect(TRUE, r);
3035 expect(0, rect.left);
3036 expect(0, rect.top);
3037 /* precise value differs for 2k, XP and Vista */
3038 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3039 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3041 DestroyWindow(hwnd);
3044 static void test_getitemposition(void)
3046 HWND hwnd, header;
3047 DWORD r;
3048 POINT pt;
3049 RECT rect;
3051 hwnd = create_listview_control(0);
3052 ok(hwnd != NULL, "failed to create a listview window\n");
3053 header = subclass_header(hwnd);
3055 /* LVS_REPORT, single item, no columns added */
3056 insert_item(hwnd, 0);
3058 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3060 pt.x = pt.y = -1;
3061 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3062 expect(TRUE, r);
3063 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3065 /* LVS_REPORT, single item, single column */
3066 insert_column(hwnd, 0);
3068 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3070 pt.x = pt.y = -1;
3071 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3072 expect(TRUE, r);
3073 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3075 memset(&rect, 0, sizeof(rect));
3076 SendMessage(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3077 /* some padding? */
3078 expect(2, pt.x);
3079 /* offset by header height */
3080 expect(rect.bottom - rect.top, pt.y);
3082 DestroyWindow(hwnd);
3085 static void test_columnscreation(void)
3087 HWND hwnd, header;
3088 DWORD r;
3090 hwnd = create_listview_control(0);
3091 ok(hwnd != NULL, "failed to create a listview window\n");
3093 insert_item(hwnd, 0);
3095 /* headers columns aren't created automatically */
3096 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3097 ok(IsWindow(header), "Expected header handle\n");
3098 r = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
3099 expect(0, r);
3101 DestroyWindow(hwnd);
3104 static void test_getitemrect(void)
3106 HWND hwnd;
3107 HIMAGELIST himl;
3108 HBITMAP hbm;
3109 RECT rect;
3110 DWORD r;
3111 LVITEMA item;
3112 LVCOLUMNA col;
3113 INT order[2];
3114 POINT pt;
3116 hwnd = create_listview_control(0);
3117 ok(hwnd != NULL, "failed to create a listview window\n");
3119 /* empty item */
3120 memset(&item, 0, sizeof(item));
3121 item.iItem = 0;
3122 item.iSubItem = 0;
3123 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3124 expect(0, r);
3126 rect.left = LVIR_BOUNDS;
3127 rect.right = rect.top = rect.bottom = -1;
3128 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3129 expect(TRUE, r);
3131 /* zero width rectangle with no padding */
3132 expect(0, rect.left);
3133 expect(0, rect.right);
3135 insert_column(hwnd, 0);
3136 insert_column(hwnd, 1);
3138 col.mask = LVCF_WIDTH;
3139 col.cx = 50;
3140 r = SendMessage(hwnd, LVM_SETCOLUMN, 0, (LPARAM)&col);
3141 expect(TRUE, r);
3143 col.mask = LVCF_WIDTH;
3144 col.cx = 100;
3145 r = SendMessage(hwnd, LVM_SETCOLUMN, 1, (LPARAM)&col);
3146 expect(TRUE, r);
3148 rect.left = LVIR_BOUNDS;
3149 rect.right = rect.top = rect.bottom = -1;
3150 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3151 expect(TRUE, r);
3153 /* still no left padding */
3154 expect(0, rect.left);
3155 expect(150, rect.right);
3157 rect.left = LVIR_SELECTBOUNDS;
3158 rect.right = rect.top = rect.bottom = -1;
3159 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3160 expect(TRUE, r);
3161 /* padding */
3162 expect(2, rect.left);
3164 rect.left = LVIR_LABEL;
3165 rect.right = rect.top = rect.bottom = -1;
3166 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3167 expect(TRUE, r);
3168 /* padding, column width */
3169 expect(2, rect.left);
3170 expect(50, rect.right);
3172 /* no icons attached */
3173 rect.left = LVIR_ICON;
3174 rect.right = rect.top = rect.bottom = -1;
3175 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3176 expect(TRUE, r);
3177 /* padding */
3178 expect(2, rect.left);
3179 expect(2, rect.right);
3181 /* change order */
3182 order[0] = 1; order[1] = 0;
3183 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3184 expect(TRUE, r);
3185 pt.x = -1;
3186 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3187 expect(TRUE, r);
3188 /* 1 indexed column width + padding */
3189 expect(102, pt.x);
3190 /* rect is at zero too */
3191 rect.left = LVIR_BOUNDS;
3192 rect.right = rect.top = rect.bottom = -1;
3193 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3194 expect(TRUE, r);
3195 expect(0, rect.left);
3196 /* just width sum */
3197 expect(150, rect.right);
3199 rect.left = LVIR_SELECTBOUNDS;
3200 rect.right = rect.top = rect.bottom = -1;
3201 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3202 expect(TRUE, r);
3203 /* column width + padding */
3204 expect(102, rect.left);
3206 /* back to initial order */
3207 order[0] = 0; order[1] = 1;
3208 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3209 expect(TRUE, r);
3211 /* state icons */
3212 himl = ImageList_Create(16, 16, 0, 2, 2);
3213 ok(himl != NULL, "failed to create imagelist\n");
3214 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3215 ok(hbm != NULL, "failed to create bitmap\n");
3216 r = ImageList_Add(himl, hbm, 0);
3217 ok(r == 0, "should be zero\n");
3218 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3219 ok(hbm != NULL, "failed to create bitmap\n");
3220 r = ImageList_Add(himl, hbm, 0);
3221 ok(r == 1, "should be one\n");
3223 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3224 ok(r == 0, "should return zero\n");
3226 item.mask = LVIF_STATE;
3227 item.state = INDEXTOSTATEIMAGEMASK(1);
3228 item.stateMask = LVIS_STATEIMAGEMASK;
3229 item.iItem = 0;
3230 item.iSubItem = 0;
3231 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3232 expect(TRUE, r);
3234 /* icon bounds */
3235 rect.left = LVIR_ICON;
3236 rect.right = rect.top = rect.bottom = -1;
3237 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3238 expect(TRUE, r);
3239 /* padding + stateicon width */
3240 expect(18, rect.left);
3241 expect(18, rect.right);
3242 /* label bounds */
3243 rect.left = LVIR_LABEL;
3244 rect.right = rect.top = rect.bottom = -1;
3245 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3246 expect(TRUE, r);
3247 /* padding + stateicon width -> column width */
3248 expect(18, rect.left);
3249 expect(50, rect.right);
3251 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)NULL);
3252 ok(r != 0, "should return current list handle\n");
3254 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3255 ok(r == 0, "should return zero\n");
3257 item.mask = LVIF_STATE | LVIF_IMAGE;
3258 item.iImage = 1;
3259 item.state = 0;
3260 item.stateMask = ~0;
3261 item.iItem = 0;
3262 item.iSubItem = 0;
3263 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3264 expect(TRUE, r);
3266 /* icon bounds */
3267 rect.left = LVIR_ICON;
3268 rect.right = rect.top = rect.bottom = -1;
3269 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3270 expect(TRUE, r);
3271 /* padding, icon width */
3272 expect(2, rect.left);
3273 expect(18, rect.right);
3274 /* label bounds */
3275 rect.left = LVIR_LABEL;
3276 rect.right = rect.top = rect.bottom = -1;
3277 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3278 expect(TRUE, r);
3279 /* padding + icon width -> column width */
3280 expect(18, rect.left);
3281 expect(50, rect.right);
3283 /* select bounds */
3284 rect.left = LVIR_SELECTBOUNDS;
3285 rect.right = rect.top = rect.bottom = -1;
3286 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3287 expect(TRUE, r);
3288 /* padding, column width */
3289 expect(2, rect.left);
3290 expect(50, rect.right);
3292 /* try with indentation */
3293 item.mask = LVIF_INDENT;
3294 item.iIndent = 1;
3295 item.iItem = 0;
3296 item.iSubItem = 0;
3297 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3298 expect(TRUE, r);
3300 /* bounds */
3301 rect.left = LVIR_BOUNDS;
3302 rect.right = rect.top = rect.bottom = -1;
3303 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3304 expect(TRUE, r);
3305 /* padding + 1 icon width, column width */
3306 expect(0, rect.left);
3307 expect(150, rect.right);
3309 /* select bounds */
3310 rect.left = LVIR_SELECTBOUNDS;
3311 rect.right = rect.top = rect.bottom = -1;
3312 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3313 expect(TRUE, r);
3314 /* padding + 1 icon width, column width */
3315 expect(2 + 16, rect.left);
3316 expect(50, rect.right);
3318 /* label bounds */
3319 rect.left = LVIR_LABEL;
3320 rect.right = rect.top = rect.bottom = -1;
3321 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3322 expect(TRUE, r);
3323 /* padding + 2 icon widths, column width */
3324 expect(2 + 16*2, rect.left);
3325 expect(50, rect.right);
3327 /* icon bounds */
3328 rect.left = LVIR_ICON;
3329 rect.right = rect.top = rect.bottom = -1;
3330 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3331 expect(TRUE, r);
3332 /* padding + 1 icon width indentation, icon width */
3333 expect(2 + 16, rect.left);
3334 expect(34, rect.right);
3337 DestroyWindow(hwnd);
3340 static void test_editbox(void)
3342 HWND hwnd, hwndedit, hwndedit2;
3343 LVITEMA item;
3344 DWORD r;
3345 static CHAR testitemA[] = "testitem";
3346 static CHAR testitem1A[] = "testitem1";
3347 static CHAR buffer[10];
3349 hwnd = create_listview_control(LVS_EDITLABELS);
3350 ok(hwnd != NULL, "failed to create a listview window\n");
3352 insert_column(hwnd, 0);
3354 memset(&item, 0, sizeof(item));
3355 item.mask = LVIF_TEXT;
3356 item.pszText = testitemA;
3357 item.iItem = 0;
3358 item.iSubItem = 0;
3359 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3360 expect(0, r);
3362 /* setting focus is necessary */
3363 SetFocus(hwnd);
3364 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3365 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3367 /* modify initial string */
3368 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
3369 expect(TRUE, r);
3370 /* return focus to listview */
3371 SetFocus(hwnd);
3373 memset(&item, 0, sizeof(item));
3374 item.mask = LVIF_TEXT;
3375 item.pszText = buffer;
3376 item.cchTextMax = 10;
3377 item.iItem = 0;
3378 item.iSubItem = 0;
3379 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3380 expect(TRUE, r);
3382 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3384 /* send LVM_EDITLABEL on already created edit */
3385 SetFocus(hwnd);
3386 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3387 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3388 /* focus will be set to edit */
3389 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
3390 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3391 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
3393 /* creating label disabled when control isn't focused */
3394 SetFocus(0);
3395 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3396 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3398 /* check EN_KILLFOCUS handling */
3399 memset(&item, 0, sizeof(item));
3400 item.pszText = testitemA;
3401 item.iItem = 0;
3402 item.iSubItem = 0;
3403 r = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3404 expect(TRUE, r);
3406 SetFocus(hwnd);
3407 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3408 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3409 /* modify edit and notify control that it lost focus */
3410 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
3411 expect(TRUE, r);
3412 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
3413 expect(0, r);
3414 memset(&item, 0, sizeof(item));
3415 item.pszText = buffer;
3416 item.cchTextMax = 10;
3417 item.iItem = 0;
3418 item.iSubItem = 0;
3419 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3420 expect(lstrlen(item.pszText), r);
3421 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3422 /* end edit without saving */
3423 r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
3424 expect(0, r);
3425 memset(&item, 0, sizeof(item));
3426 item.pszText = buffer;
3427 item.cchTextMax = 10;
3428 item.iItem = 0;
3429 item.iSubItem = 0;
3430 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3431 expect(lstrlen(item.pszText), r);
3432 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3434 /* LVM_EDITLABEL with -1 destroys current edit */
3435 hwndedit = (HWND)SendMessage(hwnd, LVM_GETEDITCONTROL, 0, 0);
3436 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3437 /* no edit present */
3438 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
3439 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3440 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3441 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3442 /* edit present */
3443 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3444 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
3445 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3446 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3447 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3448 /* check another negative value */
3449 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3450 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3451 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3452 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -2, 0);
3453 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3454 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3455 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3456 /* and value greater than max item index */
3457 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3458 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3459 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3460 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
3461 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, r, 0);
3462 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3463 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3464 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3466 /* messaging tests */
3467 SetFocus(hwnd);
3468 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3469 blockEdit = FALSE;
3470 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3471 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3472 /* testing only sizing messages */
3473 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
3474 "edit box create - sizing", FALSE);
3476 DestroyWindow(hwnd);
3479 static void test_notifyformat(void)
3481 HWND hwnd, header;
3482 DWORD r;
3484 hwnd = create_listview_control(0);
3485 ok(hwnd != NULL, "failed to create a listview window\n");
3487 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
3488 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
3489 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3490 expect(0, r);
3491 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
3492 /* set */
3493 r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
3494 expect(0, r);
3495 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3496 if (r == 1)
3498 r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
3499 expect(1, r);
3500 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3501 expect(0, r);
3503 else
3505 win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
3506 DestroyWindow(hwnd);
3507 return;
3510 DestroyWindow(hwnd);
3512 /* test failure in parent WM_NOTIFYFORMAT */
3513 notifyFormat = 0;
3514 hwnd = create_listview_control(0);
3515 ok(hwnd != NULL, "failed to create a listview window\n");
3516 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3517 ok(IsWindow(header), "expected header to be created\n");
3518 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3519 expect(0, r);
3520 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3521 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3522 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
3523 ok(r != 0, "Expected valid format\n");
3525 notifyFormat = NFR_UNICODE;
3526 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
3527 expect(NFR_UNICODE, r);
3528 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3529 expect(1, r);
3530 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3531 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3533 notifyFormat = NFR_ANSI;
3534 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
3535 expect(NFR_ANSI, r);
3536 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3537 expect(0, r);
3538 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3539 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3541 DestroyWindow(hwnd);
3543 /* try different unicode window combination and defaults */
3544 if (!GetModuleHandleW(NULL))
3546 win_skip("Additional notify format tests are incompatible with Win9x\n");
3547 return;
3550 hwndparentW = create_parent_window(TRUE);
3551 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
3552 if (!IsWindow(hwndparentW)) return;
3554 notifyFormat = -1;
3555 hwnd = create_listview_controlW(0, hwndparentW);
3556 ok(hwnd != NULL, "failed to create a listview window\n");
3557 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3558 ok(IsWindow(header), "expected header to be created\n");
3559 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3560 expect(1, r);
3561 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3562 expect(1, r);
3563 DestroyWindow(hwnd);
3564 /* receiving error code defaulting to ansi */
3565 notifyFormat = 0;
3566 hwnd = create_listview_controlW(0, hwndparentW);
3567 ok(hwnd != NULL, "failed to create a listview window\n");
3568 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3569 ok(IsWindow(header), "expected header to be created\n");
3570 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3571 expect(0, r);
3572 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3573 expect(1, r);
3574 DestroyWindow(hwnd);
3575 /* receiving ansi code from unicode window, use it */
3576 notifyFormat = NFR_ANSI;
3577 hwnd = create_listview_controlW(0, hwndparentW);
3578 ok(hwnd != NULL, "failed to create a listview window\n");
3579 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3580 ok(IsWindow(header), "expected header to be created\n");
3581 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3582 expect(0, r);
3583 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3584 expect(1, r);
3585 DestroyWindow(hwnd);
3586 /* unicode listview with ansi parent window */
3587 notifyFormat = -1;
3588 hwnd = create_listview_controlW(0, hwndparent);
3589 ok(hwnd != NULL, "failed to create a listview window\n");
3590 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3591 ok(IsWindow(header), "expected header to be created\n");
3592 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3593 expect(0, r);
3594 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3595 expect(1, r);
3596 DestroyWindow(hwnd);
3597 /* unicode listview with ansi parent window, return error code */
3598 notifyFormat = 0;
3599 hwnd = create_listview_controlW(0, hwndparent);
3600 ok(hwnd != NULL, "failed to create a listview window\n");
3601 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3602 ok(IsWindow(header), "expected header to be created\n");
3603 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3604 expect(0, r);
3605 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3606 expect(1, r);
3607 DestroyWindow(hwnd);
3609 DestroyWindow(hwndparentW);
3612 static void test_indentation(void)
3614 HWND hwnd;
3615 LVITEMA item;
3616 DWORD r;
3618 hwnd = create_listview_control(0);
3619 ok(hwnd != NULL, "failed to create a listview window\n");
3621 memset(&item, 0, sizeof(item));
3622 item.mask = LVIF_INDENT;
3623 item.iItem = 0;
3624 item.iIndent = I_INDENTCALLBACK;
3625 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3626 expect(0, r);
3628 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3630 item.iItem = 0;
3631 item.mask = LVIF_INDENT;
3632 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
3633 expect(TRUE, r);
3635 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3636 "get indent dispinfo", FALSE);
3638 DestroyWindow(hwnd);
3641 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
3643 return 0;
3646 static BOOL is_below_comctl_5(void)
3648 HWND hwnd;
3649 BOOL ret;
3651 hwnd = create_listview_control(0);
3652 ok(hwnd != NULL, "failed to create a listview window\n");
3653 insert_item(hwnd, 0);
3655 ret = SendMessage(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
3657 DestroyWindow(hwnd);
3659 return !ret;
3662 static void test_get_set_view(void)
3664 HWND hwnd;
3665 DWORD ret;
3666 DWORD_PTR style;
3668 /* test style->view mapping */
3669 hwnd = create_listview_control(0);
3670 ok(hwnd != NULL, "failed to create a listview window\n");
3672 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3673 expect(LV_VIEW_DETAILS, ret);
3675 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3676 /* LVS_ICON == 0 */
3677 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_REPORT);
3678 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3679 expect(LV_VIEW_ICON, ret);
3681 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3682 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_SMALLICON);
3683 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3684 expect(LV_VIEW_SMALLICON, ret);
3686 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3687 SetWindowLongPtr(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
3688 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3689 expect(LV_VIEW_LIST, ret);
3691 /* switching view doesn't touch window style */
3692 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
3693 expect(1, ret);
3694 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3695 ok(style & LVS_LIST, "Expected style to be preserved\n");
3696 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
3697 expect(1, ret);
3698 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3699 ok(style & LVS_LIST, "Expected style to be preserved\n");
3700 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
3701 expect(1, ret);
3702 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3703 ok(style & LVS_LIST, "Expected style to be preserved\n");
3705 DestroyWindow(hwnd);
3708 static void test_canceleditlabel(void)
3710 HWND hwnd, hwndedit;
3711 DWORD ret;
3712 CHAR buff[10];
3713 LVITEMA itema;
3714 static CHAR test[] = "test";
3715 static const CHAR test1[] = "test1";
3717 hwnd = create_listview_control(LVS_EDITLABELS);
3718 ok(hwnd != NULL, "failed to create a listview window\n");
3720 insert_item(hwnd, 0);
3722 /* try without edit created */
3723 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
3724 expect(TRUE, ret);
3726 /* cancel without data change */
3727 SetFocus(hwnd);
3728 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3729 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
3730 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
3731 expect(TRUE, ret);
3732 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
3734 /* cancel after data change */
3735 memset(&itema, 0, sizeof(itema));
3736 itema.pszText = test;
3737 ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
3738 expect(TRUE, ret);
3739 SetFocus(hwnd);
3740 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3741 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
3742 ret = SetWindowText(hwndedit, test1);
3743 ok(ret != 0, "Expected edit text to change\n");
3744 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
3745 expect(TRUE, ret);
3746 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
3747 memset(&itema, 0, sizeof(itema));
3748 itema.pszText = buff;
3749 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
3750 ret = SendMessage(hwnd, LVM_GETITEMTEXT, 0, (LPARAM)&itema);
3751 expect(5, ret);
3752 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
3754 DestroyWindow(hwnd);
3757 static void test_mapidindex(void)
3759 HWND hwnd;
3760 DWORD ret;
3762 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
3763 hwnd = create_listview_control(LVS_OWNERDATA);
3764 ok(hwnd != NULL, "failed to create a listview window\n");
3765 insert_item(hwnd, 0);
3766 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3767 expect(-1, ret);
3768 DestroyWindow(hwnd);
3770 hwnd = create_listview_control(0);
3771 ok(hwnd != NULL, "failed to create a listview window\n");
3773 /* LVM_MAPINDEXTOID with invalid index */
3774 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3775 expect(-1, ret);
3777 insert_item(hwnd, 0);
3778 insert_item(hwnd, 1);
3780 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0);
3781 expect(-1, ret);
3782 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0);
3783 expect(-1, ret);
3785 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3786 expect(0, ret);
3787 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
3788 expect(1, ret);
3789 /* remove 0 indexed item, id retained */
3790 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
3791 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3792 expect(1, ret);
3793 /* new id starts from previous value */
3794 insert_item(hwnd, 1);
3795 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
3796 expect(2, ret);
3798 /* get index by id */
3799 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0);
3800 expect(-1, ret);
3801 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0);
3802 expect(-1, ret);
3803 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0);
3804 expect(0, ret);
3805 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0);
3806 expect(1, ret);
3808 DestroyWindow(hwnd);
3811 static void test_getitemspacing(void)
3813 HWND hwnd;
3814 DWORD ret;
3815 INT cx, cy;
3816 HIMAGELIST himl;
3817 HBITMAP hbmp;
3818 LVITEMA itema;
3820 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
3821 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
3823 /* LVS_ICON */
3824 hwnd = create_custom_listview_control(0);
3825 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3826 todo_wine {
3827 expect(cx, LOWORD(ret));
3828 expect(cy, HIWORD(ret));
3830 /* now try with icons */
3831 himl = ImageList_Create(40, 40, 0, 4, 4);
3832 ok(himl != NULL, "failed to create imagelist\n");
3833 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
3834 ok(hbmp != NULL, "failed to create bitmap\n");
3835 ret = ImageList_Add(himl, hbmp, 0);
3836 expect(0, ret);
3837 ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
3838 expect(0, ret);
3840 itema.mask = LVIF_IMAGE;
3841 itema.iImage = 0;
3842 itema.iItem = 0;
3843 itema.iSubItem = 0;
3844 ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
3845 expect(0, ret);
3846 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3847 todo_wine {
3848 /* spacing + icon size returned */
3849 expect(cx + 40, LOWORD(ret));
3850 expect(cy + 40, HIWORD(ret));
3852 DestroyWindow(hwnd);
3853 /* LVS_SMALLICON */
3854 hwnd = create_custom_listview_control(LVS_SMALLICON);
3855 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3856 todo_wine {
3857 expect(cx, LOWORD(ret));
3858 expect(cy, HIWORD(ret));
3860 DestroyWindow(hwnd);
3861 /* LVS_REPORT */
3862 hwnd = create_custom_listview_control(LVS_REPORT);
3863 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3864 todo_wine {
3865 expect(cx, LOWORD(ret));
3866 expect(cy, HIWORD(ret));
3868 DestroyWindow(hwnd);
3869 /* LVS_LIST */
3870 hwnd = create_custom_listview_control(LVS_LIST);
3871 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3872 todo_wine {
3873 expect(cx, LOWORD(ret));
3874 expect(cy, HIWORD(ret));
3876 DestroyWindow(hwnd);
3879 static void test_getcolumnwidth(void)
3881 HWND hwnd;
3882 DWORD ret;
3883 DWORD_PTR style;
3884 LVCOLUMNA col;
3886 /* default column width */
3887 hwnd = create_custom_listview_control(0);
3888 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3889 expect(0, ret);
3890 style = GetWindowLong(hwnd, GWL_STYLE);
3891 SetWindowLong(hwnd, GWL_STYLE, style | LVS_LIST);
3892 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3893 todo_wine expect(8, ret);
3894 style = GetWindowLong(hwnd, GWL_STYLE) & ~LVS_LIST;
3895 SetWindowLong(hwnd, GWL_STYLE, style | LVS_REPORT);
3896 col.mask = 0;
3897 ret = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
3898 expect(0, ret);
3899 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3900 expect(10, ret);
3901 DestroyWindow(hwnd);
3904 static void test_scrollnotify(void)
3906 HWND hwnd;
3907 DWORD ret;
3909 hwnd = create_listview_control(0);
3911 insert_column(hwnd, 0);
3912 insert_column(hwnd, 1);
3913 insert_item(hwnd, 0);
3915 /* make it scrollable - resize */
3916 ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3917 expect(TRUE, ret);
3918 ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3919 expect(TRUE, ret);
3921 /* try with dummy call */
3922 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3923 ret = SendMessage(hwnd, LVM_SCROLL, 0, 0);
3924 expect(TRUE, ret);
3925 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
3926 "scroll notify 1", TRUE);
3928 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3929 ret = SendMessage(hwnd, LVM_SCROLL, 1, 0);
3930 expect(TRUE, ret);
3931 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
3932 "scroll notify 2", TRUE);
3934 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3935 ret = SendMessage(hwnd, LVM_SCROLL, 1, 1);
3936 expect(TRUE, ret);
3937 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
3938 "scroll notify 3", TRUE);
3940 DestroyWindow(hwnd);
3943 static void test_LVS_EX_TRANSPARENTBKGND(void)
3945 HWND hwnd;
3946 DWORD ret;
3947 HDC hdc;
3949 hwnd = create_listview_control(0);
3951 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
3952 expect(TRUE, ret);
3954 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
3955 LVS_EX_TRANSPARENTBKGND);
3957 ret = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
3958 if (ret != CLR_NONE)
3960 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
3961 DestroyWindow(hwnd);
3962 return;
3965 /* try to set some back color and check this style bit */
3966 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
3967 expect(TRUE, ret);
3968 ret = SendMessage(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
3969 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
3971 /* now test what this style actually does */
3972 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
3973 LVS_EX_TRANSPARENTBKGND);
3975 hdc = GetWindowDC(hwndparent);
3977 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3978 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3979 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
3980 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
3982 ReleaseDC(hwndparent, hdc);
3984 DestroyWindow(hwnd);
3987 static void test_ApproximateViewRect(void)
3989 HWND hwnd;
3990 DWORD ret;
3991 INT cx, cy;
3992 HIMAGELIST himl;
3993 HBITMAP hbmp;
3994 LVITEMA itema;
3995 static CHAR test[] = "abracadabra, a very long item label";
3997 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
3998 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4000 hwnd = create_custom_listview_control(LVS_ICON);
4001 himl = ImageList_Create(40, 40, 0, 4, 4);
4002 ok(himl != NULL, "failed to create imagelist\n");
4003 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4004 ok(hbmp != NULL, "failed to create bitmap\n");
4005 ret = ImageList_Add(himl, hbmp, 0);
4006 expect(0, ret);
4007 ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4008 expect(0, ret);
4010 itema.mask = LVIF_IMAGE;
4011 itema.iImage = 0;
4012 itema.iItem = 0;
4013 itema.iSubItem = 0;
4014 ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
4015 expect(0, ret);
4017 ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
4018 if (ret == 0)
4020 /* version 4.0 */
4021 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
4022 return;
4025 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4026 ok(MAKELONG(77,827)==ret,"Incorrect Approximate rect\n");
4028 ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
4029 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4030 ok(MAKELONG(102,302)==ret,"Incorrect Approximate rect\n");
4032 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4033 ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
4035 itema.pszText = test;
4036 ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
4037 expect(TRUE, ret);
4038 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4039 ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
4041 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
4042 ok(MAKELONG(52,2)==ret,"Incorrect Approximate rect\n");
4043 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
4044 ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
4045 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
4046 ok(MAKELONG(102,52)==ret,"Incorrect Approximate rect\n");
4047 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
4048 ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n");
4049 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
4050 ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n");
4051 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
4052 ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n");
4053 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
4054 ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n");
4055 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
4056 ok(MAKELONG(152,152)==ret,"Incorrect Approximate rect\n");
4058 DestroyWindow(hwnd);
4061 START_TEST(listview)
4063 HMODULE hComctl32;
4064 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
4066 ULONG_PTR ctx_cookie;
4067 HANDLE hCtx;
4068 HWND hwnd;
4070 hComctl32 = GetModuleHandleA("comctl32.dll");
4071 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
4072 if (pInitCommonControlsEx)
4074 INITCOMMONCONTROLSEX iccex;
4075 iccex.dwSize = sizeof(iccex);
4076 iccex.dwICC = ICC_LISTVIEW_CLASSES;
4077 pInitCommonControlsEx(&iccex);
4079 else
4080 InitCommonControls();
4082 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
4084 hwndparent = create_parent_window(FALSE);
4085 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4087 g_is_below_5 = is_below_comctl_5();
4089 test_images();
4090 test_checkboxes();
4091 test_items();
4092 test_create();
4093 test_redraw();
4094 test_customdraw();
4095 test_icon_spacing();
4096 test_color();
4097 test_item_count();
4098 test_item_position();
4099 test_columns();
4100 test_getorigin();
4101 test_multiselect();
4102 test_getitemrect();
4103 test_subitem_rect();
4104 test_sorting();
4105 test_ownerdata();
4106 test_norecompute();
4107 test_nosortheader();
4108 test_setredraw();
4109 test_hittest();
4110 test_getviewrect();
4111 test_getitemposition();
4112 test_columnscreation();
4113 test_editbox();
4114 test_notifyformat();
4115 test_indentation();
4116 test_getitemspacing();
4117 test_getcolumnwidth();
4118 test_ApproximateViewRect();
4120 if (!load_v6_module(&ctx_cookie, &hCtx))
4122 DestroyWindow(hwndparent);
4123 return;
4126 /* this is a XP SP3 failure workaround */
4127 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
4128 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
4129 0, 0, 100, 100,
4130 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
4131 if (!IsWindow(hwnd))
4133 win_skip("FIXME: failed to create ListView window.\n");
4134 unload_v6_module(ctx_cookie, hCtx);
4135 DestroyWindow(hwndparent);
4136 return;
4138 else
4139 DestroyWindow(hwnd);
4141 /* comctl32 version 6 tests start here */
4142 test_get_set_view();
4143 test_canceleditlabel();
4144 test_mapidindex();
4145 test_scrollnotify();
4146 test_LVS_EX_TRANSPARENTBKGND();
4148 unload_v6_module(ctx_cookie, hCtx);
4150 DestroyWindow(hwndparent);