4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * Copyright 2009-2011 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
27 #include "wine/test.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 COMBINED_SEQ_INDEX 4
36 #define NUM_MSG_SEQUENCES 5
41 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
42 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
43 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
45 static const WCHAR testparentclassW[] =
46 {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
48 static HWND hwndparent, hwndparentW;
49 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
50 static BOOL blockEdit;
51 /* return nonzero on NM_HOVER */
52 static BOOL g_block_hover;
53 /* dumps LVN_ITEMCHANGED message data */
54 static BOOL g_dump_itemchanged;
55 /* format reported to control:
56 -1 falls to defproc, anything else returned */
57 static INT notifyFormat;
58 /* indicates we're running < 5.80 version */
59 static BOOL g_is_below_5;
60 /* item data passed to LVN_GETDISPINFOA */
61 static LVITEMA g_itema;
62 /* alter notification code A->W */
63 static BOOL g_disp_A_to_W;
64 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
65 static NMLVDISPINFO g_editbox_disp_info;
67 static HWND subclass_editbox(HWND hwndListview);
69 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
71 static const struct message create_ownerdrawfixed_parent_seq[] = {
72 { WM_NOTIFYFORMAT, sent },
73 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
74 { WM_MEASUREITEM, sent },
75 { WM_PARENTNOTIFY, sent },
79 static const struct message redraw_listview_seq[] = {
80 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
81 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
82 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
83 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
84 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
85 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
86 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
90 static const struct message listview_icon_spacing_seq[] = {
91 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
92 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
93 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
97 static const struct message listview_color_seq[] = {
98 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
99 { LVM_GETBKCOLOR, sent },
100 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
101 { LVM_GETTEXTCOLOR, sent },
102 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
103 { LVM_GETTEXTBKCOLOR, sent },
105 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
106 { LVM_GETBKCOLOR, sent },
107 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
108 { LVM_GETTEXTCOLOR, sent },
109 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
110 { LVM_GETTEXTBKCOLOR, sent },
112 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
113 { LVM_GETBKCOLOR, sent },
114 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
115 { LVM_GETTEXTCOLOR, sent },
116 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
117 { LVM_GETTEXTBKCOLOR, sent },
119 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
120 { LVM_GETBKCOLOR, sent },
121 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
122 { LVM_GETTEXTCOLOR, sent },
123 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
124 { LVM_GETTEXTBKCOLOR, sent },
128 static const struct message listview_item_count_seq[] = {
129 { LVM_GETITEMCOUNT, sent },
130 { LVM_INSERTITEM, sent },
131 { LVM_INSERTITEM, sent },
132 { LVM_INSERTITEM, sent },
133 { LVM_GETITEMCOUNT, sent },
134 { LVM_DELETEITEM, sent|wparam, 2 },
135 { WM_NCPAINT, sent|optional },
136 { WM_ERASEBKGND, sent|optional },
137 { LVM_GETITEMCOUNT, sent },
138 { LVM_DELETEALLITEMS, sent },
139 { LVM_GETITEMCOUNT, sent },
140 { LVM_INSERTITEM, sent },
141 { LVM_INSERTITEM, sent },
142 { LVM_GETITEMCOUNT, sent },
143 { LVM_INSERTITEM, sent },
144 { LVM_GETITEMCOUNT, sent },
148 static const struct message listview_itempos_seq[] = {
149 { LVM_INSERTITEM, sent },
150 { LVM_INSERTITEM, sent },
151 { LVM_INSERTITEM, sent },
152 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
153 { WM_NCPAINT, sent|optional },
154 { WM_ERASEBKGND, sent|optional },
155 { LVM_GETITEMPOSITION, sent|wparam, 1 },
156 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
157 { LVM_GETITEMPOSITION, sent|wparam, 2 },
158 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
159 { LVM_GETITEMPOSITION, sent|wparam, 0 },
163 static const struct message listview_ownerdata_switchto_seq[] = {
164 { WM_STYLECHANGING, sent },
165 { WM_STYLECHANGED, sent },
169 static const struct message listview_getorderarray_seq[] = {
170 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
171 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
175 static const struct message empty_seq[] = {
179 static const struct message forward_erasebkgnd_parent_seq[] = {
180 { WM_ERASEBKGND, sent },
184 static const struct message ownderdata_select_focus_parent_seq[] = {
185 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
186 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
187 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
191 static const struct message ownerdata_setstate_all_parent_seq[] = {
192 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
196 static const struct message ownerdata_defocus_all_parent_seq[] = {
197 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
198 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
199 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
200 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
204 static const struct message ownerdata_deselect_all_parent_seq[] = {
205 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
206 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
210 static const struct message select_all_parent_seq[] = {
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 },
217 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
218 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
220 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
221 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
223 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
224 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
228 static const struct message textcallback_set_again_parent_seq[] = {
229 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
230 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
234 static const struct message single_getdispinfo_parent_seq[] = {
235 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
239 static const struct message getitemposition_seq1[] = {
240 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
244 static const struct message getitemposition_seq2[] = {
245 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
246 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
250 static const struct message editbox_create_pos[] = {
251 /* sequence sent after LVN_BEGINLABELEDIT */
252 /* next two are 4.7x specific */
253 { WM_WINDOWPOSCHANGING, sent },
254 { WM_WINDOWPOSCHANGED, sent|optional },
256 { WM_WINDOWPOSCHANGING, sent|optional },
257 { WM_NCCALCSIZE, sent },
258 { WM_WINDOWPOSCHANGED, sent },
259 { WM_MOVE, sent|defwinproc },
260 { WM_SIZE, sent|defwinproc },
261 /* the rest is todo, skipped in 4.7x */
262 { WM_WINDOWPOSCHANGING, sent|optional },
263 { WM_WINDOWPOSCHANGED, sent|optional },
267 static const struct message scroll_parent_seq[] = {
268 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
269 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
273 static const struct message setredraw_seq[] = {
274 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
278 static const struct message lvs_ex_transparentbkgnd_seq[] = {
279 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
283 static const struct message edit_end_nochange[] = {
284 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
285 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
286 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
290 static const struct message hover_parent[] = {
291 { WM_GETDLGCODE, sent }, /* todo_wine */
292 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
296 static const struct message listview_destroy[] = {
297 { 0x0090, sent|optional }, /* Vista */
298 { WM_PARENTNOTIFY, sent },
299 { WM_SHOWWINDOW, sent },
300 { WM_WINDOWPOSCHANGING, sent },
301 { WM_WINDOWPOSCHANGED, sent|optional },
302 { WM_DESTROY, sent },
303 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
304 { WM_NCDESTROY, sent },
308 static const struct message listview_header_changed_seq[] = {
309 { LVM_SETCOLUMNA, sent },
310 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
311 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
315 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
317 static LONG defwndproc_counter = 0;
321 msg.message = message;
322 msg.flags = sent|wparam|lparam;
323 if (defwndproc_counter) msg.flags |= defwinproc;
326 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
328 /* log system messages, except for painting */
329 if (message < WM_USER &&
330 message != WM_PAINT &&
331 message != WM_ERASEBKGND &&
332 message != WM_NCPAINT &&
333 message != WM_NCHITTEST &&
334 message != WM_GETTEXT &&
335 message != WM_GETICON &&
336 message != WM_DEVICECHANGE)
338 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
340 add_message(sequences, PARENT_SEQ_INDEX, &msg);
341 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
343 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
349 switch (((NMHDR*)lParam)->code)
351 case LVN_BEGINLABELEDIT:
355 /* subclass edit box */
357 edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
361 INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
362 ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
363 "text limit %d, expected 259\n", len);
368 case LVN_ENDLABELEDIT:
372 /* always accept new item text */
373 NMLVDISPINFO *di = (NMLVDISPINFO*)lParam;
374 g_editbox_disp_info = *di;
375 trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText);
377 /* edit control still available from this notification */
378 edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
379 ok(IsWindow(edit), "expected valid edit control handle\n");
380 ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
384 case LVN_BEGINSCROLL:
387 NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
389 trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
390 "BEGIN" : "END", pScroll->dx, pScroll->dy);
393 case LVN_ITEMCHANGED:
394 if (g_dump_itemchanged)
396 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
397 trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
398 nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
401 case LVN_GETDISPINFOA:
403 NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
404 g_itema = dispinfo->item;
406 if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
408 static const WCHAR testW[] = {'T','E','S','T',0};
409 dispinfo->hdr.code = LVN_GETDISPINFOW;
410 memcpy(dispinfo->item.pszText, testW, sizeof(testW));
413 /* test control buffer size for text, 10 used to mask cases when control
414 is using caller buffer to process LVM_GETITEM for example */
415 if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
416 ok(dispinfo->item.cchTextMax == 260 ||
417 broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
418 "buffer size %d\n", dispinfo->item.cchTextMax);
422 if (g_block_hover) return 1;
427 case WM_NOTIFYFORMAT:
429 /* force to return format */
430 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
435 defwndproc_counter++;
436 ret = DefWindowProcA(hwnd, message, wParam, lParam);
437 defwndproc_counter--;
442 static BOOL register_parent_wnd_class(BOOL Unicode)
450 clsW.lpfnWndProc = parent_wnd_proc;
453 clsW.hInstance = GetModuleHandleW(NULL);
455 clsW.hCursor = LoadCursorA(0, IDC_ARROW);
456 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
457 clsW.lpszMenuName = NULL;
458 clsW.lpszClassName = testparentclassW;
463 clsA.lpfnWndProc = parent_wnd_proc;
466 clsA.hInstance = GetModuleHandleA(NULL);
468 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
469 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
470 clsA.lpszMenuName = NULL;
471 clsA.lpszClassName = "Listview test parent class";
474 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
477 static HWND create_parent_window(BOOL Unicode)
479 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
482 if (!register_parent_wnd_class(Unicode))
489 hwnd = CreateWindowExW(0, testparentclassW, nameW,
490 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
491 WS_MAXIMIZEBOX | WS_VISIBLE,
493 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
495 hwnd = CreateWindowExA(0, "Listview test parent class",
496 "Listview test parent window",
497 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
498 WS_MAXIMIZEBOX | WS_VISIBLE,
500 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
501 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
505 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
507 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
508 static LONG defwndproc_counter = 0;
512 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
514 /* some debug output for style changing */
515 if ((message == WM_STYLECHANGING ||
516 message == WM_STYLECHANGED) && lParam)
518 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
519 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
522 msg.message = message;
523 msg.flags = sent|wparam|lparam;
524 if (defwndproc_counter) msg.flags |= defwinproc;
527 msg.id = LISTVIEW_ID;
528 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
529 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
531 defwndproc_counter++;
532 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
533 defwndproc_counter--;
537 static HWND create_listview_control(DWORD style)
543 GetClientRect(hwndparent, &rect);
544 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
545 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
546 0, 0, rect.right, rect.bottom,
547 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
548 ok(hwnd != NULL, "gle=%d\n", GetLastError());
550 if (!hwnd) return NULL;
552 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
553 (LONG_PTR)listview_subclass_proc);
554 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
559 /* unicode listview window with specified parent */
560 static HWND create_listview_controlW(DWORD style, HWND parent)
565 static const WCHAR nameW[] = {'f','o','o',0};
567 GetClientRect(parent, &rect);
568 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
569 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
570 0, 0, rect.right, rect.bottom,
571 parent, NULL, GetModuleHandleW(NULL), NULL);
572 ok(hwnd != NULL, "gle=%d\n", GetLastError());
574 if (!hwnd) return NULL;
576 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
577 (LONG_PTR)listview_subclass_proc);
578 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
583 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
585 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
586 static LONG defwndproc_counter = 0;
590 trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
592 msg.message = message;
593 msg.flags = sent|wparam|lparam;
594 if (defwndproc_counter) msg.flags |= defwinproc;
598 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
600 defwndproc_counter++;
601 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
602 defwndproc_counter--;
606 static HWND subclass_header(HWND hwndListview)
611 hwnd = ListView_GetHeader(hwndListview);
612 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
613 (LONG_PTR)header_subclass_proc);
614 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
619 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
621 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
622 static LONG defwndproc_counter = 0;
626 msg.message = message;
627 msg.flags = sent|wparam|lparam;
628 if (defwndproc_counter) msg.flags |= defwinproc;
632 /* all we need is sizing */
633 if (message == WM_WINDOWPOSCHANGING ||
634 message == WM_NCCALCSIZE ||
635 message == WM_WINDOWPOSCHANGED ||
636 message == WM_MOVE ||
639 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
642 defwndproc_counter++;
643 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
644 defwndproc_counter--;
648 static HWND subclass_editbox(HWND hwndListview)
653 hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0);
654 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
655 (LONG_PTR)editbox_subclass_proc);
656 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
661 /* Performs a single LVM_HITTEST test */
662 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
663 BOOL todo_item, BOOL todo_flags, int line)
672 ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
678 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
679 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
680 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
685 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
686 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
687 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
693 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
695 else if (broken_flags)
696 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
697 "Expected flags %x, got %x\n", flags, lpht.flags);
699 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
702 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
704 /* Performs a single LVM_SUBITEMHITTEST test */
705 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
706 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
714 ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
720 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
721 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
726 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
727 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
733 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
736 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
741 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
744 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
747 #define test_lvm_subitemhittest(a,b,c,d,e,f,g,h,i) test_lvm_subitemhittest_(a,b,c,d,e,f,g,h,i,__LINE__)
749 static void test_images(void)
757 static CHAR hello[] = "hello";
759 himl = ImageList_Create(40, 40, 0, 4, 4);
760 ok(himl != NULL, "failed to create imagelist\n");
762 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
763 ok(hbmp != NULL, "failed to create bitmap\n");
765 r = ImageList_Add(himl, hbmp, 0);
766 ok(r == 0, "should be zero\n");
768 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
769 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
770 ok(hwnd != NULL, "failed to create listview window\n");
772 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
773 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
775 ok(r == 0, "should return zero\n");
777 r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
778 ok(r == 0, "should return zero\n");
780 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
781 ok(r != 0, "got 0\n");
783 /* returns dimensions */
785 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
786 ok(r == 0, "should be zero items\n");
788 item.mask = LVIF_IMAGE | LVIF_TEXT;
793 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
794 ok(r == -1, "should fail\n");
797 item.pszText = hello;
798 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
799 ok(r == 0, "should not fail\n");
801 memset(&r1, 0, sizeof r1);
803 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
806 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
807 ok(r == TRUE, "should not fail\n");
810 item.pszText = hello;
811 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
812 ok(r == 0, "should not fail\n");
814 memset(&r2, 0, sizeof r2);
816 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
819 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
824 static void test_checkboxes(void)
829 static CHAR text[] = "Text",
833 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
834 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
835 ok(hwnd != NULL, "failed to create listview window\n");
837 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
838 item.mask = LVIF_TEXT | LVIF_STATE;
839 item.stateMask = 0xffff;
844 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
848 item.mask = LVIF_STATE;
849 item.stateMask = 0xffff;
850 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
852 ok(item.state == 0xfccc, "state %x\n", item.state);
854 /* Don't set LVIF_STATE */
855 item.mask = LVIF_TEXT;
856 item.stateMask = 0xffff;
861 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
865 item.mask = LVIF_STATE;
866 item.stateMask = 0xffff;
867 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
869 ok(item.state == 0, "state %x\n", item.state);
871 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
874 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
876 item.mask = LVIF_STATE;
877 item.stateMask = 0xffff;
878 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
880 if (item.state != 0x1ccc)
882 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
887 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
889 item.mask = LVIF_TEXT;
891 item.pszText = text2;
892 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
896 item.mask = LVIF_STATE;
897 item.stateMask = 0xffff;
898 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
900 ok(item.state == 0x1000, "state %x\n", item.state);
902 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
904 item.mask = LVIF_TEXT | LVIF_STATE;
905 item.stateMask = 0xffff;
907 item.pszText = text3;
908 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
912 item.mask = LVIF_STATE;
913 item.stateMask = 0xffff;
914 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
916 ok(item.state == 0x1aaa, "state %x\n", item.state);
918 /* Set an item's state to checked */
920 item.mask = LVIF_STATE;
921 item.stateMask = 0xf000;
923 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
927 item.mask = LVIF_STATE;
928 item.stateMask = 0xffff;
929 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
931 ok(item.state == 0x2aaa, "state %x\n", item.state);
933 /* Check that only the bits we asked for are returned,
934 * and that all the others are set to zero
937 item.mask = LVIF_STATE;
938 item.stateMask = 0xf000;
940 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
942 ok(item.state == 0x2000, "state %x\n", item.state);
944 /* Set the style again and check that doesn't change an item's state */
945 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
946 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
949 item.mask = LVIF_STATE;
950 item.stateMask = 0xffff;
951 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
953 ok(item.state == 0x2aaa, "state %x\n", item.state);
955 /* Unsetting the checkbox extended style doesn't change an item's state */
956 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
957 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
960 item.mask = LVIF_STATE;
961 item.stateMask = 0xffff;
962 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
964 ok(item.state == 0x2aaa, "state %x\n", item.state);
966 /* Now setting the style again will change an item's state */
967 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
971 item.mask = LVIF_STATE;
972 item.stateMask = 0xffff;
973 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
975 ok(item.state == 0x1aaa, "state %x\n", item.state);
977 /* Toggle checkbox tests (bug 9934) */
978 memset (&item, 0xcc, sizeof(item));
979 item.mask = LVIF_STATE;
982 item.state = LVIS_FOCUSED;
983 item.stateMask = LVIS_FOCUSED;
984 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
988 item.mask = LVIF_STATE;
989 item.stateMask = 0xffff;
990 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
992 ok(item.state == 0x1aab, "state %x\n", item.state);
994 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
996 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
1000 item.mask = LVIF_STATE;
1001 item.stateMask = 0xffff;
1002 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1004 ok(item.state == 0x2aab, "state %x\n", item.state);
1006 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1008 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
1012 item.mask = LVIF_STATE;
1013 item.stateMask = 0xffff;
1014 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1016 ok(item.state == 0x1aab, "state %x\n", item.state);
1018 DestroyWindow(hwnd);
1021 static void insert_column(HWND hwnd, int idx)
1026 memset(&column, 0xcc, sizeof(column));
1027 column.mask = LVCF_SUBITEM;
1028 column.iSubItem = idx;
1030 rc = ListView_InsertColumn(hwnd, idx, &column);
1034 static void insert_item(HWND hwnd, int idx)
1036 static CHAR text[] = "foo";
1041 memset(&item, 0xcc, sizeof (item));
1042 item.mask = LVIF_TEXT;
1045 item.pszText = text;
1047 rc = ListView_InsertItem(hwnd, &item);
1051 static void test_items(void)
1053 const LPARAM lparamTest = 0x42;
1054 static CHAR text[] = "Text";
1060 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
1061 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1062 ok(hwnd != NULL, "failed to create listview window\n");
1065 * Test setting/getting item params
1068 /* Set up two columns */
1069 insert_column(hwnd, 0);
1070 insert_column(hwnd, 1);
1072 /* LVIS_SELECTED with zero stateMask */
1074 memset (&item, 0, sizeof (item));
1075 item.mask = LVIF_STATE;
1076 item.state = LVIS_SELECTED;
1080 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1083 memset (&item, 0xcc, sizeof (item));
1084 item.mask = LVIF_STATE;
1085 item.stateMask = LVIS_SELECTED;
1089 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1091 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1092 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1094 /* LVIS_SELECTED with zero stateMask */
1096 memset (&item, 0, sizeof (item));
1097 item.mask = LVIF_STATE;
1098 item.state = LVIS_FOCUSED;
1102 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1105 memset (&item, 0xcc, sizeof (item));
1106 item.mask = LVIF_STATE;
1107 item.stateMask = LVIS_FOCUSED;
1111 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1113 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1114 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1116 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1118 memset (&item, 0, sizeof (item));
1119 item.mask = LVIF_STATE;
1120 item.state = LVIS_CUT;
1121 item.stateMask = LVIS_FOCUSED;
1124 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1127 memset (&item, 0xcc, sizeof (item));
1128 item.mask = LVIF_STATE;
1129 item.stateMask = LVIS_CUT;
1133 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1135 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1136 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1138 /* Insert an item with just a param */
1139 memset (&item, 0xcc, sizeof (item));
1140 item.mask = LVIF_PARAM;
1143 item.lParam = lparamTest;
1144 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1147 /* Test getting of the param */
1148 memset (&item, 0xcc, sizeof (item));
1149 item.mask = LVIF_PARAM;
1152 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1154 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1156 /* Set up a subitem */
1157 memset (&item, 0xcc, sizeof (item));
1158 item.mask = LVIF_TEXT;
1161 item.pszText = text;
1162 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1165 item.mask = LVIF_TEXT;
1168 item.pszText = buffA;
1169 item.cchTextMax = sizeof(buffA);
1170 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1172 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1174 /* set up with extra flag */
1175 /* 1. reset subitem text */
1176 item.mask = LVIF_TEXT;
1179 item.pszText = NULL;
1180 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1183 item.mask = LVIF_TEXT;
1186 item.pszText = buffA;
1188 item.cchTextMax = sizeof(buffA);
1189 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1191 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1193 /* 2. set new text with extra flag specified */
1194 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1197 item.pszText = text;
1198 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1199 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1203 item.mask = LVIF_TEXT;
1206 item.pszText = buffA;
1208 item.cchTextMax = sizeof(buffA);
1209 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1211 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1214 /* Query param from subitem: returns main item param */
1215 memset (&item, 0xcc, sizeof (item));
1216 item.mask = LVIF_PARAM;
1219 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1221 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1223 /* Set up param on first subitem: no effect */
1224 memset (&item, 0xcc, sizeof (item));
1225 item.mask = LVIF_PARAM;
1228 item.lParam = lparamTest+1;
1229 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1232 /* Query param from subitem again: should still return main item param */
1233 memset (&item, 0xcc, sizeof (item));
1234 item.mask = LVIF_PARAM;
1237 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1239 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1241 /**** Some tests of state highlighting ****/
1242 memset (&item, 0xcc, sizeof (item));
1243 item.mask = LVIF_STATE;
1246 item.state = LVIS_SELECTED;
1247 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1248 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1251 item.state = LVIS_DROPHILITED;
1252 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1255 memset (&item, 0xcc, sizeof (item));
1256 item.mask = LVIF_STATE;
1259 item.stateMask = -1;
1260 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1262 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1264 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1266 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1268 /* some notnull but meaningless masks */
1269 memset (&item, 0, sizeof(item));
1270 item.mask = LVIF_NORECOMPUTE;
1273 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1275 memset (&item, 0, sizeof(item));
1276 item.mask = LVIF_DI_SETITEM;
1279 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1282 /* set text to callback value already having it */
1283 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1285 memset (&item, 0, sizeof (item));
1286 item.mask = LVIF_TEXT;
1287 item.pszText = LPSTR_TEXTCALLBACK;
1289 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1291 memset (&item, 0, sizeof (item));
1293 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1295 item.pszText = LPSTR_TEXTCALLBACK;
1296 r = SendMessage(hwnd, LVM_SETITEMTEXT, 0 , (LPARAM) &item);
1299 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1300 "check callback text comparison rule", FALSE);
1302 DestroyWindow(hwnd);
1305 static void test_columns(void)
1314 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1315 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1316 ok(hwnd != NULL, "failed to create listview window\n");
1318 /* Add a column with no mask */
1319 memset(&column, 0xcc, sizeof(column));
1321 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1322 ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1324 /* Check its width */
1325 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1326 ok(rc == 10 || broken(rc == 0) /* win9x */,
1327 "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1329 DestroyWindow(hwnd);
1331 /* LVM_GETCOLUMNORDERARRAY */
1332 hwnd = create_listview_control(LVS_REPORT);
1333 subclass_header(hwnd);
1335 memset(&column, 0, sizeof(column));
1336 column.mask = LVCF_WIDTH;
1338 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1342 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1345 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1347 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1349 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1350 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1352 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1354 /* after column added subitem is considered as present */
1355 insert_item(hwnd, 0);
1357 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1359 item.pszText = buff;
1360 item.cchTextMax = sizeof(buff);
1363 item.mask = LVIF_TEXT;
1364 memset(&g_itema, 0, sizeof(g_itema));
1365 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1367 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1369 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1370 "get subitem text after column added", FALSE);
1372 DestroyWindow(hwnd);
1375 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1376 static WNDPROC listviewWndProc;
1377 static HIMAGELIST test_create_imagelist;
1379 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1383 if (uMsg == WM_CREATE)
1385 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
1386 lpcs->style |= LVS_REPORT;
1388 ret = CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
1389 if (uMsg == WM_CREATE) SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1393 static void test_create(void)
1404 cls.cbSize = sizeof(WNDCLASSEX);
1405 ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1406 listviewWndProc = cls.lpfnWndProc;
1407 cls.lpfnWndProc = create_test_wndproc;
1408 cls.lpszClassName = "MyListView32";
1409 ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
1411 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1412 hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1413 ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1414 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1416 if (!IsWindow(hHeader))
1419 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1420 DestroyWindow(hList);
1424 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1425 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1426 DestroyWindow(hList);
1428 /* header isn't created on LVS_ICON and LVS_LIST styles */
1429 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1430 GetModuleHandle(NULL), 0);
1431 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1432 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1433 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1435 memset(&col, 0, sizeof(LVCOLUMNA));
1436 col.mask = LVCF_WIDTH;
1438 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1440 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1441 ok(IsWindow(hHeader), "Header should be created\n");
1442 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1443 style = GetWindowLong(hHeader, GWL_STYLE);
1444 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1445 DestroyWindow(hList);
1447 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1448 GetModuleHandle(NULL), 0);
1449 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1450 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1451 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1453 memset(&col, 0, sizeof(LVCOLUMNA));
1454 col.mask = LVCF_WIDTH;
1456 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1458 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1459 ok(IsWindow(hHeader), "Header should be created\n");
1460 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1461 DestroyWindow(hList);
1463 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1464 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1465 GetModuleHandle(NULL), 0);
1466 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLongPtr(hList, GWL_STYLE) | LVS_REPORT);
1467 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1468 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1469 ok(IsWindow(hHeader), "Header should be created\n");
1470 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLong(hList, GWL_STYLE) & ~LVS_REPORT);
1471 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1472 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1473 ok(IsWindow(hHeader), "Header should be created\n");
1474 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1475 DestroyWindow(hList);
1477 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1478 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1479 GetModuleHandle(NULL), 0);
1480 ret = SetWindowLongPtr(hList, GWL_STYLE,
1481 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1482 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1483 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1484 ok(IsWindow(hHeader), "Header should be created\n");
1485 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1486 ret = SetWindowLongPtr(hList, GWL_STYLE,
1487 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1488 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1489 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1490 ok(IsWindow(hHeader), "Header should be created\n");
1491 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1492 DestroyWindow(hList);
1494 /* LVS_REPORT without WS_VISIBLE */
1495 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1496 GetModuleHandle(NULL), 0);
1497 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1498 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1499 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1501 memset(&col, 0, sizeof(LVCOLUMNA));
1502 col.mask = LVCF_WIDTH;
1504 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1506 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1507 ok(IsWindow(hHeader), "Header should be created\n");
1508 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1509 DestroyWindow(hList);
1511 /* LVS_REPORT without WS_VISIBLE, try to show it */
1512 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1513 GetModuleHandle(NULL), 0);
1514 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1515 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1516 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1517 ShowWindow(hList, SW_SHOW);
1518 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1519 ok(IsWindow(hHeader), "Header should be created\n");
1520 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1521 DestroyWindow(hList);
1523 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1524 hList = CreateWindow("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1525 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1526 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1527 ok(IsWindow(hHeader), "Header should be created\n");
1528 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1529 /* HDS_DRAGDROP set by default */
1530 ok(GetWindowLongPtr(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1531 DestroyWindow(hList);
1533 /* setting LVS_EX_HEADERDRAGDROP creates header */
1534 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1535 GetModuleHandle(NULL), 0);
1536 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1537 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1538 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1539 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1540 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1541 ok(IsWindow(hHeader) ||
1542 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1543 "Header should be created\n");
1544 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1545 DestroyWindow(hList);
1547 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1548 hList = create_listview_control(LVS_ICON);
1549 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1550 r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1551 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1552 DestroyWindow(hList);
1554 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1555 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1556 GetModuleHandle(NULL), 0);
1557 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1558 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1560 rect.left = LVIR_BOUNDS;
1562 rect.right = rect.bottom = -10;
1563 r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1566 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1567 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1568 ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1570 DestroyWindow(hList);
1572 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1573 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1574 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1575 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1576 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1577 DestroyWindow(hList);
1580 static void test_redraw(void)
1587 hwnd = create_listview_control(LVS_REPORT);
1588 subclass_header(hwnd);
1590 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1592 InvalidateRect(hwnd, NULL, TRUE);
1594 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1596 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1598 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1599 /* 1. Without backbuffer */
1600 res = ListView_SetBkColor(hwnd, CLR_NONE);
1603 hdc = GetWindowDC(hwndparent);
1605 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1606 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1607 ok(r == 1, "Expected not zero result\n");
1608 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1609 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1611 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1614 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1615 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1617 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1618 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1620 /* 2. With backbuffer */
1621 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1622 LVS_EX_DOUBLEBUFFER);
1623 res = ListView_SetBkColor(hwnd, CLR_NONE);
1626 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1627 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1629 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1630 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1632 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1635 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1636 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1637 todo_wine expect(1, r);
1638 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1639 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1641 ReleaseDC(hwndparent, hdc);
1643 DestroyWindow(hwnd);
1646 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1648 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1650 if(msg == WM_NOTIFY) {
1651 NMHDR *nmhdr = (PVOID)lp;
1652 if(nmhdr->code == NM_CUSTOMDRAW) {
1653 NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
1654 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
1655 switch(nmlvcd->nmcd.dwDrawStage) {
1657 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1658 return CDRF_NOTIFYITEMDRAW;
1659 case CDDS_ITEMPREPAINT:
1660 nmlvcd->clrTextBk = CLR_DEFAULT;
1661 return CDRF_NOTIFYSUBITEMDRAW;
1662 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1663 clr = GetBkColor(nmlvcd->nmcd.hdc);
1664 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1665 return CDRF_NOTIFYPOSTPAINT;
1666 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1667 clr = GetBkColor(nmlvcd->nmcd.hdc);
1668 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1669 return CDRF_DODEFAULT;
1671 return CDRF_DODEFAULT;
1675 return DefWindowProcA(hwnd, msg, wp, lp);
1678 static void test_customdraw(void)
1683 hwnd = create_listview_control(LVS_REPORT);
1685 insert_column(hwnd, 0);
1686 insert_column(hwnd, 1);
1687 insert_item(hwnd, 0);
1689 oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
1690 (LONG_PTR)cd_wndproc);
1692 InvalidateRect(hwnd, NULL, TRUE);
1695 SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1697 DestroyWindow(hwnd);
1700 static void test_icon_spacing(void)
1702 /* LVM_SETICONSPACING */
1703 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1709 hwnd = create_listview_control(LVS_ICON);
1710 ok(hwnd != NULL, "failed to create a listview window\n");
1712 r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1713 expect(NFR_ANSI, r);
1715 /* reset the icon spacing to defaults */
1716 SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1718 /* now we can request what the defaults are */
1719 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1723 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1725 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1726 ok(r == MAKELONG(w, h) ||
1727 broken(r == MAKELONG(w, w)), /* win98 */
1728 "Expected %d, got %d\n", MAKELONG(w, h), r);
1730 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1734 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1735 DestroyWindow(hwnd);
1738 expect(MAKELONG(20,30), r);
1740 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1741 expect(MAKELONG(25,35), r);
1743 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1745 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1746 DestroyWindow(hwnd);
1749 static void test_color(void)
1757 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1759 hwnd = create_listview_control(LVS_REPORT);
1760 ok(hwnd != NULL, "failed to create a listview window\n");
1762 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1764 for (i = 0; i < 4; i++)
1768 r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
1770 r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
1773 r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
1775 r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1778 r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1780 r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1784 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1785 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1787 /* invalidation test done separately to avoid a message chain mess */
1788 r = ValidateRect(hwnd, NULL);
1790 r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
1793 rect.right = rect.bottom = 1;
1794 r = GetUpdateRect(hwnd, &rect, TRUE);
1795 todo_wine expect(FALSE, r);
1796 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1798 r = ValidateRect(hwnd, NULL);
1800 r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
1803 rect.right = rect.bottom = 1;
1804 r = GetUpdateRect(hwnd, &rect, TRUE);
1805 todo_wine expect(FALSE, r);
1806 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1808 r = ValidateRect(hwnd, NULL);
1810 r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
1813 rect.right = rect.bottom = 1;
1814 r = GetUpdateRect(hwnd, &rect, TRUE);
1815 todo_wine expect(FALSE, r);
1816 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1818 DestroyWindow(hwnd);
1821 static void test_item_count(void)
1823 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1836 static CHAR item0text[] = "item0";
1837 static CHAR item1text[] = "item1";
1838 static CHAR item2text[] = "item2";
1840 hwnd = create_listview_control(LVS_REPORT);
1841 ok(hwnd != NULL, "failed to create a listview window\n");
1843 /* resize in dpiaware manner to fit all 3 items added */
1845 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
1846 GetTextMetricsA(hdc, &tm);
1847 /* 2 extra pixels for bounds and header border */
1848 height = tm.tmHeight + 2;
1849 SelectObject(hdc, hOldFont);
1852 GetWindowRect(hwnd, &rect);
1853 /* 3 items + 1 header + 1 to be sure */
1854 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
1856 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1858 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1862 item0.mask = LVIF_TEXT;
1865 item0.pszText = item0text;
1866 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1869 /* [item0, item1] */
1870 item1.mask = LVIF_TEXT;
1873 item1.pszText = item1text;
1874 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1877 /* [item0, item1, item2] */
1878 item2.mask = LVIF_TEXT;
1881 item2.pszText = item2text;
1882 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1885 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1888 /* [item0, item1] */
1889 r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0);
1892 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1896 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1899 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1903 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1906 /* [item0, item1] */
1907 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1910 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1913 /* [item0, item1, item2] */
1914 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1917 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1920 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
1922 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1923 DestroyWindow(hwnd);
1926 static void test_item_position(void)
1928 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1937 static CHAR item0text[] = "item0";
1938 static CHAR item1text[] = "item1";
1939 static CHAR item2text[] = "item2";
1941 hwnd = create_listview_control(LVS_ICON);
1942 ok(hwnd != NULL, "failed to create a listview window\n");
1944 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1947 item0.mask = LVIF_TEXT;
1950 item0.pszText = item0text;
1951 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1954 /* [item0, item1] */
1955 item1.mask = LVIF_TEXT;
1958 item1.pszText = item1text;
1959 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1962 /* [item0, item1, item2] */
1963 item2.mask = LVIF_TEXT;
1966 item2.pszText = item2text;
1967 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1970 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
1972 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
1974 expect2(10, 5, position.x, position.y);
1976 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
1978 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
1980 expect2(0, 0, position.x, position.y);
1982 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
1984 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
1986 expect2(20, 20, position.x, position.y);
1988 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
1990 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1991 DestroyWindow(hwnd);
1994 static void test_getorigin(void)
2002 position.x = position.y = 0;
2004 hwnd = create_listview_control(LVS_ICON);
2005 ok(hwnd != NULL, "failed to create a listview window\n");
2006 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2008 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2010 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2011 DestroyWindow(hwnd);
2013 hwnd = create_listview_control(LVS_SMALLICON);
2014 ok(hwnd != NULL, "failed to create a listview window\n");
2015 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2017 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2019 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2020 DestroyWindow(hwnd);
2022 hwnd = create_listview_control(LVS_LIST);
2023 ok(hwnd != NULL, "failed to create a listview window\n");
2024 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2026 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2028 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2029 DestroyWindow(hwnd);
2031 hwnd = create_listview_control(LVS_REPORT);
2032 ok(hwnd != NULL, "failed to create a listview window\n");
2033 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2035 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2037 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2038 DestroyWindow(hwnd);
2041 static void test_multiselect(void)
2043 typedef struct t_select_task
2054 int i,j,item_count,selected_count;
2055 static const int items=5;
2061 static struct t_select_task task_list[] = {
2062 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2063 { "using VK_UP", -1, VK_UP, -1, -1 },
2064 { "using VK_END", 0, VK_END, 1, -1 },
2065 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2069 hwnd = create_listview_control(LVS_REPORT);
2071 for (i=0;i<items;i++) {
2072 insert_item(hwnd, 0);
2075 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2077 expect(items,item_count);
2080 task = task_list[i];
2082 /* deselect all items */
2083 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
2084 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2086 /* set initial position */
2087 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2088 ListView_SetItemState(hwnd,(task.initPos == -1 ? item_count -1 : task.initPos),LVIS_SELECTED ,LVIS_SELECTED);
2090 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2092 ok(selected_count == 1, "There should be only one selected item at the beginning (is %d)\n",selected_count);
2094 /* Set SHIFT key pressed */
2095 GetKeyboardState(kstate);
2096 kstate[VK_SHIFT]=0x80;
2097 SetKeyboardState(kstate);
2099 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2100 r = SendMessage(hwnd, WM_KEYDOWN, task.loopVK, 0);
2102 r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
2106 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2108 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);
2110 /* Set SHIFT key released */
2111 GetKeyboardState(kstate);
2112 kstate[VK_SHIFT]=0x00;
2113 SetKeyboardState(kstate);
2115 DestroyWindow(hwnd);
2117 /* make multiple selection, then switch to LVS_SINGLESEL */
2118 hwnd = create_listview_control(LVS_REPORT);
2119 for (i=0;i<items;i++) {
2120 insert_item(hwnd, 0);
2122 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2123 expect(items,item_count);
2125 /* try with NULL pointer */
2126 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2129 /* select all, check notifications */
2130 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
2132 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2134 item.stateMask = LVIS_SELECTED;
2135 item.state = LVIS_SELECTED;
2136 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2139 ok_sequence(sequences, PARENT_SEQ_INDEX, select_all_parent_seq,
2140 "select all notification", FALSE);
2142 /* deselect all items */
2143 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
2144 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2146 ListView_SetItemState(hwnd, i, LVIS_SELECTED, LVIS_SELECTED);
2149 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2151 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2154 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2155 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2156 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2157 /* check that style is accepted */
2158 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2159 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2162 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
2163 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2165 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2167 SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2170 /* select one more */
2171 ListView_SetItemState(hwnd, 3, LVIS_SELECTED, LVIS_SELECTED);
2174 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
2175 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2177 r = ListView_GetItemState(hwnd, 3, LVIS_SELECTED);
2178 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2180 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2182 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2185 /* try to select all on LVS_SINGLESEL */
2186 memset(&item, 0, sizeof(item));
2187 item.stateMask = LVIS_SELECTED;
2188 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2190 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2192 item.stateMask = LVIS_SELECTED;
2193 item.state = LVIS_SELECTED;
2194 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2197 r = ListView_GetSelectedCount(hwnd);
2199 r = ListView_GetSelectionMark(hwnd);
2202 /* try to deselect all on LVS_SINGLESEL */
2203 item.stateMask = LVIS_SELECTED;
2204 item.state = LVIS_SELECTED;
2205 r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2208 item.stateMask = LVIS_SELECTED;
2210 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2212 r = ListView_GetSelectedCount(hwnd);
2215 DestroyWindow(hwnd);
2218 static void test_subitem_rect(void)
2226 /* test LVM_GETSUBITEMRECT for header */
2227 hwnd = create_listview_control(LVS_REPORT);
2228 ok(hwnd != NULL, "failed to create a listview window\n");
2229 /* add some columns */
2230 memset(&col, 0, sizeof(LVCOLUMN));
2231 col.mask = LVCF_WIDTH;
2233 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
2236 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
2239 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
2241 /* item = -1 means header, subitem index is 1 based */
2242 rect.left = LVIR_BOUNDS;
2244 rect.right = rect.bottom = 0;
2245 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2248 rect.left = LVIR_BOUNDS;
2250 rect.right = rect.bottom = 0;
2251 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2254 expect(100, rect.left);
2255 expect(250, rect.right);
2257 expect(3, rect.top);
2259 rect.left = LVIR_BOUNDS;
2261 rect.right = rect.bottom = 0;
2262 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2265 expect(250, rect.left);
2266 expect(450, rect.right);
2268 expect(3, rect.top);
2270 /* item LVS_REPORT padding isn't applied to subitems */
2271 insert_item(hwnd, 0);
2273 rect.left = LVIR_BOUNDS;
2275 rect.right = rect.bottom = 0;
2276 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2278 expect(100, rect.left);
2279 expect(250, rect.right);
2281 rect.left = LVIR_ICON;
2283 rect.right = rect.bottom = 0;
2284 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2286 /* no icon attached - zero width rectangle, with no left padding */
2287 expect(100, rect.left);
2288 expect(100, rect.right);
2290 rect.left = LVIR_LABEL;
2292 rect.right = rect.bottom = 0;
2293 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2295 /* same as full LVIR_BOUNDS */
2296 expect(100, rect.left);
2297 expect(250, rect.right);
2299 SendMessage(hwnd, LVM_SCROLL, 10, 0);
2301 rect.left = LVIR_BOUNDS;
2303 rect.right = rect.bottom = 0;
2304 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2306 expect(90, rect.left);
2307 expect(240, rect.right);
2309 SendMessage(hwnd, LVM_SCROLL, -10, 0);
2311 DestroyWindow(hwnd);
2313 /* test subitem rects after re-arranging columns */
2314 hwnd = create_listview_control(LVS_REPORT);
2315 ok(hwnd != NULL, "failed to create a listview window\n");
2316 memset(&col, 0, sizeof(LVCOLUMN));
2317 col.mask = LVCF_WIDTH;
2320 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
2324 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
2328 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
2331 insert_item(hwnd, 0);
2332 insert_item(hwnd, 1);
2334 /* wrong item is refused for main item */
2335 rect.left = LVIR_BOUNDS;
2337 rect.right = rect.bottom = -1;
2338 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2341 /* for subitems rectangle is calculated even if there's no item added */
2342 rect.left = LVIR_BOUNDS;
2344 rect.right = rect.bottom = -1;
2345 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2348 rect2.left = LVIR_BOUNDS;
2350 rect2.right = rect2.bottom = -1;
2351 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2354 expect(rect.right, rect2.right);
2355 expect(rect.left, rect2.left);
2356 expect(rect.bottom, rect2.top);
2357 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2360 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2361 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2364 rect.left = LVIR_BOUNDS;
2366 rect.right = rect.bottom = -1;
2367 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2369 expect(0, rect.left);
2370 expect(600, rect.right);
2372 rect.left = LVIR_BOUNDS;
2374 rect.right = rect.bottom = -1;
2375 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2377 expect(0, rect.left);
2378 expect(200, rect.right);
2380 rect2.left = LVIR_BOUNDS;
2382 rect2.right = rect2.bottom = -1;
2383 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2385 expect(0, rect2.left);
2386 expect(200, rect2.right);
2387 /* items are of the same height */
2388 ok(rect2.top > 0, "expected positive item height\n");
2389 expect(rect.bottom, rect2.top);
2390 expect(rect.bottom * 2 - rect.top, rect2.bottom);
2392 rect.left = LVIR_BOUNDS;
2394 rect.right = rect.bottom = -1;
2395 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2397 expect(300, rect.left);
2398 expect(600, rect.right);
2400 DestroyWindow(hwnd);
2402 /* try it for non LVS_REPORT style */
2403 hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2404 GetModuleHandle(NULL), 0);
2405 rect.left = LVIR_BOUNDS;
2407 rect.right = rect.bottom = -10;
2408 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2410 /* rect is unchanged */
2411 expect(0, rect.left);
2412 expect(-10, rect.right);
2413 expect(1, rect.top);
2414 expect(-10, rect.bottom);
2415 DestroyWindow(hwnd);
2418 /* comparison callback for test_sorting */
2419 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2421 if (first == second) return 0;
2422 return (first > second ? 1 : -1);
2425 static void test_sorting(void)
2431 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2434 hwnd = create_listview_control(LVS_REPORT);
2435 ok(hwnd != NULL, "failed to create a listview window\n");
2437 /* insert some items */
2438 item.mask = LVIF_PARAM | LVIF_STATE;
2439 item.state = LVIS_SELECTED;
2443 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2446 item.mask = LVIF_PARAM;
2450 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2453 item.mask = LVIF_STATE | LVIF_PARAM;
2454 item.state = LVIS_SELECTED;
2458 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2461 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2464 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2467 r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2470 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2472 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2474 r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2476 r = SendMessage(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2477 expect(LVIS_SELECTED, r);
2478 r = SendMessage(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2479 expect(LVIS_SELECTED, r);
2481 DestroyWindow(hwnd);
2483 /* switch to LVS_SORTASCENDING when some items added */
2484 hwnd = create_listview_control(LVS_REPORT);
2485 ok(hwnd != NULL, "failed to create a listview window\n");
2487 item.mask = LVIF_TEXT;
2490 item.pszText = names[1];
2491 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2494 item.mask = LVIF_TEXT;
2497 item.pszText = names[2];
2498 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2501 item.mask = LVIF_TEXT;
2504 item.pszText = names[0];
2505 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2508 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2509 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2510 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2511 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2513 /* no sorting performed when switched to LVS_SORTASCENDING */
2514 item.mask = LVIF_TEXT;
2516 item.pszText = buff;
2517 item.cchTextMax = sizeof(buff);
2518 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2520 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2523 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2525 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2528 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2530 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2532 /* adding new item doesn't resort list */
2533 item.mask = LVIF_TEXT;
2536 item.pszText = names[3];
2537 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2540 item.mask = LVIF_TEXT;
2542 item.pszText = buff;
2543 item.cchTextMax = sizeof(buff);
2544 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2546 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2549 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2551 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2554 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2556 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2559 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2561 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2563 /* corner case - item should be placed at first position */
2564 item.mask = LVIF_TEXT;
2567 item.pszText = names[4];
2568 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2572 item.pszText = buff;
2573 item.cchTextMax = sizeof(buff);
2574 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2576 ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2579 item.pszText = buff;
2580 item.cchTextMax = sizeof(buff);
2581 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2583 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2586 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2588 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2591 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2593 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2596 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2598 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2600 DestroyWindow(hwnd);
2603 static void test_ownerdata(void)
2606 LONG_PTR style, ret;
2610 /* it isn't possible to set LVS_OWNERDATA after creation */
2613 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2617 hwnd = create_listview_control(LVS_REPORT);
2618 ok(hwnd != NULL, "failed to create a listview window\n");
2619 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2620 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
2622 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2624 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2625 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2626 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2627 "try to switch to LVS_OWNERDATA seq", FALSE);
2629 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2630 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
2631 DestroyWindow(hwnd);
2634 /* try to set LVS_OWNERDATA after creation just having it */
2635 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2636 ok(hwnd != NULL, "failed to create a listview window\n");
2637 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2638 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2640 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2642 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2643 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2644 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2645 "try to switch to LVS_OWNERDATA seq", FALSE);
2646 DestroyWindow(hwnd);
2648 /* try to remove LVS_OWNERDATA after creation just having it */
2651 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2655 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2656 ok(hwnd != NULL, "failed to create a listview window\n");
2657 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2658 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2660 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2662 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
2663 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2664 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2665 "try to switch to LVS_OWNERDATA seq", FALSE);
2666 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2667 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2668 DestroyWindow(hwnd);
2671 /* try select an item */
2672 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2673 ok(hwnd != NULL, "failed to create a listview window\n");
2674 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2676 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2678 memset(&item, 0, sizeof(item));
2679 item.stateMask = LVIS_SELECTED;
2680 item.state = LVIS_SELECTED;
2681 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2683 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2685 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2687 DestroyWindow(hwnd);
2689 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
2690 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2691 ok(hwnd != NULL, "failed to create a listview window\n");
2692 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2694 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2696 memset(&item, 0, sizeof(item));
2697 item.mask = LVIF_STATE;
2699 item.stateMask = LVIS_SELECTED;
2700 item.state = LVIS_SELECTED;
2701 res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2703 DestroyWindow(hwnd);
2705 /* check notifications after focused/selected changed */
2706 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2707 ok(hwnd != NULL, "failed to create a listview window\n");
2708 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
2711 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2713 memset(&item, 0, sizeof(item));
2714 item.stateMask = LVIS_SELECTED;
2715 item.state = LVIS_SELECTED;
2716 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2719 ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
2720 "ownerdata select notification", TRUE);
2722 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2724 memset(&item, 0, sizeof(item));
2725 item.stateMask = LVIS_FOCUSED;
2726 item.state = LVIS_FOCUSED;
2727 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2730 ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
2731 "ownerdata focus notification", TRUE);
2733 /* select all, check notifications */
2734 item.stateMask = LVIS_SELECTED;
2736 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2739 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2741 item.stateMask = LVIS_SELECTED;
2742 item.state = LVIS_SELECTED;
2744 g_dump_itemchanged = TRUE;
2745 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2747 g_dump_itemchanged = FALSE;
2749 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2750 "ownerdata select all notification", TRUE);
2752 /* select all again, note that all items are selected already */
2753 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2754 item.stateMask = LVIS_SELECTED;
2755 item.state = LVIS_SELECTED;
2756 g_dump_itemchanged = TRUE;
2757 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2759 g_dump_itemchanged = FALSE;
2760 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2761 "ownerdata select all notification", TRUE);
2763 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2764 item.stateMask = LVIS_SELECTED;
2766 g_dump_itemchanged = TRUE;
2767 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2769 g_dump_itemchanged = FALSE;
2770 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
2771 "ownerdata deselect all notification", TRUE);
2773 /* select one, then deselect all */
2774 item.stateMask = LVIS_SELECTED;
2775 item.state = LVIS_SELECTED;
2776 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2778 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2779 item.stateMask = LVIS_SELECTED;
2781 g_dump_itemchanged = TRUE;
2782 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2784 g_dump_itemchanged = FALSE;
2785 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
2786 "ownerdata select all notification", TRUE);
2788 /* remove focused, try to focus all */
2789 item.stateMask = LVIS_FOCUSED;
2790 item.state = LVIS_FOCUSED;
2791 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2793 item.stateMask = LVIS_FOCUSED;
2795 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2797 item.stateMask = LVIS_FOCUSED;
2798 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
2800 /* setting all to focused returns failure value */
2801 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2802 item.stateMask = LVIS_FOCUSED;
2803 item.state = LVIS_FOCUSED;
2804 g_dump_itemchanged = TRUE;
2805 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2807 g_dump_itemchanged = FALSE;
2808 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2809 "ownerdata focus all notification", FALSE);
2810 /* focus single item, remove all */
2811 item.stateMask = LVIS_FOCUSED;
2812 item.state = LVIS_FOCUSED;
2813 res = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2815 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2816 item.stateMask = LVIS_FOCUSED;
2818 g_dump_itemchanged = TRUE;
2819 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2821 g_dump_itemchanged = FALSE;
2822 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
2823 "ownerdata remove focus all notification", TRUE);
2825 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2826 item.stateMask = LVIS_CUT;
2827 item.state = LVIS_CUT;
2828 g_dump_itemchanged = TRUE;
2829 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2831 g_dump_itemchanged = FALSE;
2832 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2833 "ownerdata cut all notification", TRUE);
2834 /* all marked cut, try again */
2835 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2836 item.stateMask = LVIS_CUT;
2837 item.state = LVIS_CUT;
2838 g_dump_itemchanged = TRUE;
2839 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2841 g_dump_itemchanged = FALSE;
2842 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2843 "ownerdata cut all notification #2", TRUE);
2845 DestroyWindow(hwnd);
2847 /* check notifications on LVM_GETITEM */
2848 /* zero callback mask */
2849 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2850 ok(hwnd != NULL, "failed to create a listview window\n");
2851 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2854 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2856 memset(&item, 0, sizeof(item));
2857 item.stateMask = LVIS_SELECTED;
2858 item.mask = LVIF_STATE;
2859 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2862 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2863 "ownerdata getitem selected state 1", FALSE);
2865 /* non zero callback mask but not we asking for */
2866 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
2869 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2871 memset(&item, 0, sizeof(item));
2872 item.stateMask = LVIS_SELECTED;
2873 item.mask = LVIF_STATE;
2874 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2877 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2878 "ownerdata getitem selected state 2", FALSE);
2880 /* LVIS_OVERLAYMASK callback mask, asking for index */
2881 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2883 memset(&item, 0, sizeof(item));
2884 item.stateMask = LVIS_OVERLAYMASK;
2885 item.mask = LVIF_STATE;
2886 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2889 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
2890 "ownerdata getitem selected state 2", FALSE);
2892 DestroyWindow(hwnd);
2894 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
2895 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
2896 ok(hwnd != NULL, "failed to create a listview window\n");
2897 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2898 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2899 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2900 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
2901 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2902 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
2903 DestroyWindow(hwnd);
2904 /* apparently it's allowed to switch these style on after creation */
2905 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2906 ok(hwnd != NULL, "failed to create a listview window\n");
2907 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2908 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2909 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2910 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2911 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2912 DestroyWindow(hwnd);
2914 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2915 ok(hwnd != NULL, "failed to create a listview window\n");
2916 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2917 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2918 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
2919 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2920 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
2921 DestroyWindow(hwnd);
2924 static void test_norecompute(void)
2926 static CHAR testA[] = "test";
2932 /* self containing control */
2933 hwnd = create_listview_control(LVS_REPORT);
2934 ok(hwnd != NULL, "failed to create a listview window\n");
2935 memset(&item, 0, sizeof(item));
2936 item.mask = LVIF_TEXT | LVIF_STATE;
2938 item.stateMask = LVIS_SELECTED;
2939 item.state = LVIS_SELECTED;
2940 item.pszText = testA;
2941 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2943 /* retrieve with LVIF_NORECOMPUTE */
2944 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2946 item.pszText = buff;
2947 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2948 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2950 ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
2952 item.mask = LVIF_TEXT;
2954 item.pszText = LPSTR_TEXTCALLBACK;
2955 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2958 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2960 item.pszText = buff;
2961 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2963 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2964 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2966 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2967 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2968 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
2970 DestroyWindow(hwnd);
2973 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2974 ok(hwnd != NULL, "failed to create a listview window\n");
2976 item.mask = LVIF_STATE;
2977 item.stateMask = LVIS_SELECTED;
2978 item.state = LVIS_SELECTED;
2980 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2983 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2985 item.pszText = buff;
2986 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2987 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2988 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2990 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2991 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2992 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
2994 DestroyWindow(hwnd);
2997 static void test_nosortheader(void)
3002 hwnd = create_listview_control(LVS_REPORT);
3003 ok(hwnd != NULL, "failed to create a listview window\n");
3005 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3006 ok(IsWindow(header), "header expected\n");
3008 style = GetWindowLongPtr(header, GWL_STYLE);
3009 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3011 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3012 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3013 /* HDS_BUTTONS retained */
3014 style = GetWindowLongPtr(header, GWL_STYLE);
3015 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3017 DestroyWindow(hwnd);
3019 /* create with LVS_NOSORTHEADER */
3020 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3021 ok(hwnd != NULL, "failed to create a listview window\n");
3023 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3024 ok(IsWindow(header), "header expected\n");
3026 style = GetWindowLongPtr(header, GWL_STYLE);
3027 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3029 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3030 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3031 /* not changed here */
3032 style = GetWindowLongPtr(header, GWL_STYLE);
3033 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3035 DestroyWindow(hwnd);
3038 static void test_setredraw(void)
3046 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3047 ok(hwnd != NULL, "failed to create a listview window\n");
3049 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3050 ListView seems to handle it internally without DefWinProc */
3052 /* default value first */
3053 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
3056 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3057 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3058 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3060 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3061 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3062 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
3065 /* check update rect after redrawing */
3066 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3068 InvalidateRect(hwnd, NULL, FALSE);
3069 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3070 rect.right = rect.bottom = 1;
3071 GetUpdateRect(hwnd, &rect, FALSE);
3072 expect(0, rect.right);
3073 expect(0, rect.bottom);
3076 hdc = GetWindowDC(hwndparent);
3077 ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3079 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3081 ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3083 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
3085 ReleaseDC(hwndparent, hdc);
3087 /* check notification messages to show that repainting is disabled */
3088 ret = SendMessage(hwnd, LVM_SETITEMCOUNT, 1, 0);
3090 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3092 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3094 InvalidateRect(hwnd, NULL, TRUE);
3096 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3097 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3099 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3101 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3102 InvalidateRect(hwnd, NULL, TRUE);
3104 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3105 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3107 /* message isn't forwarded to header */
3108 subclass_header(hwnd);
3109 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3110 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3112 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3113 "WM_SETREDRAW: not forwarded to header", FALSE);
3115 DestroyWindow(hwnd);
3118 static void test_hittest(void)
3124 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3128 HIMAGELIST himl, himl2;
3131 hwnd = create_listview_control(LVS_REPORT);
3132 ok(hwnd != NULL, "failed to create a listview window\n");
3134 /* LVS_REPORT with a single subitem (2 columns) */
3135 insert_column(hwnd, 0);
3136 insert_column(hwnd, 1);
3137 insert_item(hwnd, 0);
3140 /* the only purpose of that line is to be as long as a half item rect */
3141 item.pszText = text;
3142 r = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
3145 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3147 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3150 memset(&bounds, 0, sizeof(bounds));
3151 bounds.left = LVIR_BOUNDS;
3152 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3154 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3155 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3156 r = SendMessage(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3158 ok(bounds.bottom - bounds.top == vert,
3159 "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3160 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3163 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3165 /* outside columns by x position - valid is [0, 199] */
3167 y = pos.y + (bounds.bottom - bounds.top) / 2;
3168 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3169 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3171 x = pos.x + 50; /* column half width */
3172 y = pos.y + (bounds.bottom - bounds.top) / 2;
3173 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3174 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3175 x = pos.x + 150; /* outside column */
3176 y = pos.y + (bounds.bottom - bounds.top) / 2;
3177 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3178 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3179 y = (bounds.bottom - bounds.top) / 2;
3180 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3181 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3182 /* outside possible client rectangle (to right) */
3184 y = pos.y + (bounds.bottom - bounds.top) / 2;
3185 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3186 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3187 y = (bounds.bottom - bounds.top) / 2;
3188 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3189 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3190 /* subitem returned with -1 item too */
3192 y = bounds.top - vert;
3193 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3194 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3195 /* return values appear to underflow with negative indices */
3199 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3200 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3204 /* parent client area is 100x100 by default */
3205 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3206 x = pos.x + 150; /* outside column */
3207 y = pos.y + (bounds.bottom - bounds.top) / 2;
3208 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3209 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3210 y = (bounds.bottom - bounds.top) / 2;
3211 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3212 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3213 /* the same with LVS_EX_FULLROWSELECT */
3214 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3215 x = pos.x + 150; /* outside column */
3216 y = pos.y + (bounds.bottom - bounds.top) / 2;
3217 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3218 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3219 y = (bounds.bottom - bounds.top) / 2;
3220 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3221 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3222 x = pos.x + 150; /* outside column */
3223 y = pos.y + (bounds.bottom - bounds.top) / 2;
3224 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3225 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3226 y = (bounds.bottom - bounds.top) / 2;
3227 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3228 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3229 /* outside possible client rectangle (to right) */
3231 y = pos.y + (bounds.bottom - bounds.top) / 2;
3232 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3233 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3234 y = (bounds.bottom - bounds.top) / 2;
3235 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3236 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3237 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3238 himl = ImageList_Create(16, 16, 0, 4, 4);
3239 ok(himl != NULL, "failed to create imagelist\n");
3240 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3241 ok(hbmp != NULL, "failed to create bitmap\n");
3242 r = ImageList_Add(himl, hbmp, 0);
3243 ok(r == 0, "should be zero\n");
3244 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3245 ok(hbmp != NULL, "failed to create bitmap\n");
3246 r = ImageList_Add(himl, hbmp, 0);
3247 ok(r == 1, "should be one\n");
3249 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3252 item.mask = LVIF_IMAGE;
3256 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3260 y = pos.y + (bounds.bottom - bounds.top) / 2;
3261 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3262 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3263 y = (bounds.bottom - bounds.top) / 2;
3264 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3266 /* state icons indices are 1 based, check with valid index */
3267 item.mask = LVIF_STATE;
3268 item.state = INDEXTOSTATEIMAGEMASK(1);
3269 item.stateMask = LVIS_STATEIMAGEMASK;
3272 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3276 y = pos.y + (bounds.bottom - bounds.top) / 2;
3277 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3278 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3279 y = (bounds.bottom - bounds.top) / 2;
3280 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3282 himl2 = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3283 ok(himl2 == himl, "should return handle\n");
3285 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3289 y = pos.y + (bounds.bottom - bounds.top) / 2;
3290 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3291 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3292 y = (bounds.bottom - bounds.top) / 2;
3293 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3295 DestroyWindow(hwnd);
3298 static void test_getviewrect(void)
3305 hwnd = create_listview_control(LVS_REPORT);
3306 ok(hwnd != NULL, "failed to create a listview window\n");
3309 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3312 insert_column(hwnd, 0);
3313 insert_column(hwnd, 1);
3315 memset(&item, 0, sizeof(item));
3318 SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3320 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3322 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3325 rect.left = rect.right = rect.top = rect.bottom = -1;
3326 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3328 /* left is set to (2e31-1) - XP SP2 */
3329 expect(0, rect.right);
3330 expect(0, rect.top);
3331 expect(0, rect.bottom);
3333 /* switch to LVS_ICON */
3334 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~LVS_REPORT);
3336 rect.left = rect.right = rect.top = rect.bottom = -1;
3337 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3339 expect(0, rect.left);
3340 expect(0, rect.top);
3341 /* precise value differs for 2k, XP and Vista */
3342 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3343 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3345 DestroyWindow(hwnd);
3348 static void test_getitemposition(void)
3355 hwnd = create_listview_control(LVS_REPORT);
3356 ok(hwnd != NULL, "failed to create a listview window\n");
3357 header = subclass_header(hwnd);
3359 /* LVS_REPORT, single item, no columns added */
3360 insert_item(hwnd, 0);
3362 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3365 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3367 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3369 /* LVS_REPORT, single item, single column */
3370 insert_column(hwnd, 0);
3372 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3375 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3377 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3379 memset(&rect, 0, sizeof(rect));
3380 SendMessage(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3383 /* offset by header height */
3384 expect(rect.bottom - rect.top, pt.y);
3386 DestroyWindow(hwnd);
3389 static void test_columnscreation(void)
3394 hwnd = create_listview_control(LVS_REPORT);
3395 ok(hwnd != NULL, "failed to create a listview window\n");
3397 insert_item(hwnd, 0);
3399 /* headers columns aren't created automatically */
3400 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3401 ok(IsWindow(header), "Expected header handle\n");
3402 r = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
3405 DestroyWindow(hwnd);
3408 static void test_getitemrect(void)
3411 HIMAGELIST himl, himl_ret;
3421 /* rectangle isn't empty for empty text items */
3422 hwnd = create_listview_control(LVS_LIST);
3423 memset(&item, 0, sizeof(item));
3426 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3428 rect.left = LVIR_LABEL;
3429 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3431 expect(0, rect.left);
3432 expect(0, rect.top);
3434 todo_wine expect(((GetDeviceCaps(hdc, LOGPIXELSX) + 15) / 16) * 16, rect.right);
3435 ReleaseDC(hwnd, hdc);
3436 DestroyWindow(hwnd);
3438 hwnd = create_listview_control(LVS_REPORT);
3439 ok(hwnd != NULL, "failed to create a listview window\n");
3442 memset(&item, 0, sizeof(item));
3445 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3448 rect.left = LVIR_BOUNDS;
3449 rect.right = rect.top = rect.bottom = -1;
3450 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3453 /* zero width rectangle with no padding */
3454 expect(0, rect.left);
3455 expect(0, rect.right);
3457 insert_column(hwnd, 0);
3458 insert_column(hwnd, 1);
3460 col.mask = LVCF_WIDTH;
3462 r = SendMessage(hwnd, LVM_SETCOLUMN, 0, (LPARAM)&col);
3465 col.mask = LVCF_WIDTH;
3467 r = SendMessage(hwnd, LVM_SETCOLUMN, 1, (LPARAM)&col);
3470 rect.left = LVIR_BOUNDS;
3471 rect.right = rect.top = rect.bottom = -1;
3472 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3475 /* still no left padding */
3476 expect(0, rect.left);
3477 expect(150, rect.right);
3479 rect.left = LVIR_SELECTBOUNDS;
3480 rect.right = rect.top = rect.bottom = -1;
3481 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3484 expect(2, rect.left);
3486 rect.left = LVIR_LABEL;
3487 rect.right = rect.top = rect.bottom = -1;
3488 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3490 /* padding, column width */
3491 expect(2, rect.left);
3492 expect(50, rect.right);
3494 /* no icons attached */
3495 rect.left = LVIR_ICON;
3496 rect.right = rect.top = rect.bottom = -1;
3497 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3500 expect(2, rect.left);
3501 expect(2, rect.right);
3504 order[0] = 1; order[1] = 0;
3505 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3508 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3510 /* 1 indexed column width + padding */
3512 /* rect is at zero too */
3513 rect.left = LVIR_BOUNDS;
3514 rect.right = rect.top = rect.bottom = -1;
3515 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3517 expect(0, rect.left);
3518 /* just width sum */
3519 expect(150, rect.right);
3521 rect.left = LVIR_SELECTBOUNDS;
3522 rect.right = rect.top = rect.bottom = -1;
3523 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3525 /* column width + padding */
3526 expect(102, rect.left);
3528 /* back to initial order */
3529 order[0] = 0; order[1] = 1;
3530 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3534 himl = ImageList_Create(16, 16, 0, 2, 2);
3535 ok(himl != NULL, "failed to create imagelist\n");
3536 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3537 ok(hbm != NULL, "failed to create bitmap\n");
3538 r = ImageList_Add(himl, hbm, 0);
3540 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3541 ok(hbm != NULL, "failed to create bitmap\n");
3542 r = ImageList_Add(himl, hbm, 0);
3545 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3548 item.mask = LVIF_STATE;
3549 item.state = INDEXTOSTATEIMAGEMASK(1);
3550 item.stateMask = LVIS_STATEIMAGEMASK;
3553 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3557 rect.left = LVIR_ICON;
3558 rect.right = rect.top = rect.bottom = -1;
3559 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3561 /* padding + stateicon width */
3562 expect(18, rect.left);
3563 expect(18, rect.right);
3565 rect.left = LVIR_LABEL;
3566 rect.right = rect.top = rect.bottom = -1;
3567 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3569 /* padding + stateicon width -> column width */
3570 expect(18, rect.left);
3571 expect(50, rect.right);
3573 himl_ret = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3574 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
3576 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3579 item.mask = LVIF_STATE | LVIF_IMAGE;
3582 item.stateMask = ~0;
3585 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3589 rect.left = LVIR_ICON;
3590 rect.right = rect.top = rect.bottom = -1;
3591 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3593 /* padding, icon width */
3594 expect(2, rect.left);
3595 expect(18, rect.right);
3597 rect.left = LVIR_LABEL;
3598 rect.right = rect.top = rect.bottom = -1;
3599 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3601 /* padding + icon width -> column width */
3602 expect(18, rect.left);
3603 expect(50, rect.right);
3606 rect.left = LVIR_SELECTBOUNDS;
3607 rect.right = rect.top = rect.bottom = -1;
3608 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3610 /* padding, column width */
3611 expect(2, rect.left);
3612 expect(50, rect.right);
3614 /* try with indentation */
3615 item.mask = LVIF_INDENT;
3619 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3623 rect.left = LVIR_BOUNDS;
3624 rect.right = rect.top = rect.bottom = -1;
3625 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3627 /* padding + 1 icon width, column width */
3628 expect(0, rect.left);
3629 expect(150, rect.right);
3632 rect.left = LVIR_SELECTBOUNDS;
3633 rect.right = rect.top = rect.bottom = -1;
3634 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3636 /* padding + 1 icon width, column width */
3637 expect(2 + 16, rect.left);
3638 expect(50, rect.right);
3641 rect.left = LVIR_LABEL;
3642 rect.right = rect.top = rect.bottom = -1;
3643 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3645 /* padding + 2 icon widths, column width */
3646 expect(2 + 16*2, rect.left);
3647 expect(50, rect.right);
3650 rect.left = LVIR_ICON;
3651 rect.right = rect.top = rect.bottom = -1;
3652 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3654 /* padding + 1 icon width indentation, icon width */
3655 expect(2 + 16, rect.left);
3656 expect(34, rect.right);
3658 DestroyWindow(hwnd);
3661 static void test_editbox(void)
3663 static CHAR testitemA[] = "testitem";
3664 static CHAR testitem1A[] = "testitem_quitelongname";
3665 static CHAR testitem2A[] = "testITEM_quitelongname";
3666 static CHAR buffer[25];
3667 HWND hwnd, hwndedit, hwndedit2, header;
3671 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
3672 ok(hwnd != NULL, "failed to create a listview window\n");
3674 insert_column(hwnd, 0);
3676 memset(&item, 0, sizeof(item));
3677 item.mask = LVIF_TEXT;
3678 item.pszText = testitemA;
3681 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3684 /* test notifications without edit created */
3685 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3686 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
3688 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3689 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
3690 /* same thing but with valid window */
3691 hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
3692 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
3693 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3694 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
3696 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3697 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
3698 DestroyWindow(hwndedit);
3700 /* setting focus is necessary */
3702 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3703 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3705 /* test children Z-order after Edit box created */
3706 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3707 ok(IsWindow(header), "Expected header to be created\n");
3708 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
3709 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
3711 /* modify initial string */
3712 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
3715 /* edit window is resized and repositioned,
3716 check again for Z-order - it should be preserved */
3717 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
3718 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
3720 /* return focus to listview */
3723 memset(&item, 0, sizeof(item));
3724 item.mask = LVIF_TEXT;
3725 item.pszText = buffer;
3726 item.cchTextMax = sizeof(buffer);
3729 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3732 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3734 /* send LVM_EDITLABEL on already created edit */
3736 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3737 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3738 /* focus will be set to edit */
3739 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
3740 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3741 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
3743 /* creating label disabled when control isn't focused */
3745 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3746 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3748 /* check EN_KILLFOCUS handling */
3749 memset(&item, 0, sizeof(item));
3750 item.pszText = testitemA;
3753 r = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3757 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3758 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3759 /* modify edit and notify control that it lost focus */
3760 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
3762 g_editbox_disp_info.item.pszText = NULL;
3763 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
3765 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
3767 memset(&item, 0, sizeof(item));
3768 item.pszText = buffer;
3769 item.cchTextMax = sizeof(buffer);
3772 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3773 expect(lstrlen(item.pszText), r);
3774 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3775 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
3777 /* change item name to differ in casing only */
3779 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3780 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3781 /* modify edit and notify control that it lost focus */
3782 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
3784 g_editbox_disp_info.item.pszText = NULL;
3785 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
3787 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
3789 memset(&item, 0, sizeof(item));
3790 item.pszText = buffer;
3791 item.cchTextMax = sizeof(buffer);
3794 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3795 expect(lstrlen(item.pszText), r);
3796 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
3797 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
3799 /* end edit without saving */
3801 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3802 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3803 r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
3805 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
3806 "edit box - end edit, no change, escape", TRUE);
3807 /* end edit with saving */
3809 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3810 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3811 r = SendMessage(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
3813 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
3814 "edit box - end edit, no change, return", TRUE);
3816 memset(&item, 0, sizeof(item));
3817 item.pszText = buffer;
3818 item.cchTextMax = sizeof(buffer);
3821 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3822 expect(lstrlen(item.pszText), r);
3823 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
3825 /* LVM_EDITLABEL with -1 destroys current edit */
3826 hwndedit = (HWND)SendMessage(hwnd, LVM_GETEDITCONTROL, 0, 0);
3827 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3828 /* no edit present */
3829 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
3830 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3831 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3832 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3834 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3835 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
3836 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3837 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3838 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3839 /* check another negative value */
3840 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3841 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3842 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3843 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -2, 0);
3844 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3845 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3846 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3847 /* and value greater than max item index */
3848 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3849 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3850 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3851 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
3852 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, r, 0);
3853 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3854 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3855 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3857 /* messaging tests */
3859 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3861 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3862 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3863 /* testing only sizing messages */
3864 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
3865 "edit box create - sizing", FALSE);
3867 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
3869 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3870 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3871 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3872 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
3874 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
3875 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
3877 DestroyWindow(hwnd);
3880 static void test_notifyformat(void)
3885 hwnd = create_listview_control(LVS_REPORT);
3886 ok(hwnd != NULL, "failed to create a listview window\n");
3888 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
3889 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
3890 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3892 SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
3894 r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
3896 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3899 r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
3901 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3906 win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
3907 DestroyWindow(hwnd);
3911 DestroyWindow(hwnd);
3913 /* test failure in parent WM_NOTIFYFORMAT */
3915 hwnd = create_listview_control(LVS_REPORT);
3916 ok(hwnd != NULL, "failed to create a listview window\n");
3917 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3918 ok(IsWindow(header), "expected header to be created\n");
3919 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3921 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3922 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3923 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
3924 ok(r != 0, "Expected valid format\n");
3926 notifyFormat = NFR_UNICODE;
3927 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
3928 expect(NFR_UNICODE, r);
3929 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3931 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3932 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3934 notifyFormat = NFR_ANSI;
3935 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
3936 expect(NFR_ANSI, r);
3937 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3939 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3940 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3942 DestroyWindow(hwnd);
3944 /* try different unicode window combination and defaults */
3945 if (!GetModuleHandleW(NULL))
3947 win_skip("Additional notify format tests are incompatible with Win9x\n");
3951 hwndparentW = create_parent_window(TRUE);
3952 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
3953 if (!IsWindow(hwndparentW)) return;
3956 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
3957 ok(hwnd != NULL, "failed to create a listview window\n");
3958 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3959 ok(IsWindow(header), "expected header to be created\n");
3960 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3962 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3964 DestroyWindow(hwnd);
3965 /* receiving error code defaulting to ansi */
3967 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
3968 ok(hwnd != NULL, "failed to create a listview window\n");
3969 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3970 ok(IsWindow(header), "expected header to be created\n");
3971 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3973 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3975 DestroyWindow(hwnd);
3976 /* receiving ansi code from unicode window, use it */
3977 notifyFormat = NFR_ANSI;
3978 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
3979 ok(hwnd != NULL, "failed to create a listview window\n");
3980 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3981 ok(IsWindow(header), "expected header to be created\n");
3982 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3984 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3986 DestroyWindow(hwnd);
3987 /* unicode listview with ansi parent window */
3989 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
3990 ok(hwnd != NULL, "failed to create a listview window\n");
3991 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3992 ok(IsWindow(header), "expected header to be created\n");
3993 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3995 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3997 DestroyWindow(hwnd);
3998 /* unicode listview with ansi parent window, return error code */
4000 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4001 ok(hwnd != NULL, "failed to create a listview window\n");
4002 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4003 ok(IsWindow(header), "expected header to be created\n");
4004 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4006 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4008 DestroyWindow(hwnd);
4010 DestroyWindow(hwndparentW);
4013 static void test_indentation(void)
4019 hwnd = create_listview_control(LVS_REPORT);
4020 ok(hwnd != NULL, "failed to create a listview window\n");
4022 memset(&item, 0, sizeof(item));
4023 item.mask = LVIF_INDENT;
4025 item.iIndent = I_INDENTCALLBACK;
4026 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4029 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4032 item.mask = LVIF_INDENT;
4033 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
4036 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4037 "get indent dispinfo", FALSE);
4039 DestroyWindow(hwnd);
4042 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4047 static BOOL is_below_comctl_5(void)
4052 hwnd = create_listview_control(LVS_REPORT);
4053 ok(hwnd != NULL, "failed to create a listview window\n");
4054 insert_item(hwnd, 0);
4056 ret = SendMessage(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4058 DestroyWindow(hwnd);
4063 static void test_get_set_view(void)
4069 /* test style->view mapping */
4070 hwnd = create_listview_control(LVS_REPORT);
4071 ok(hwnd != NULL, "failed to create a listview window\n");
4073 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4074 expect(LV_VIEW_DETAILS, ret);
4076 style = GetWindowLongPtr(hwnd, GWL_STYLE);
4078 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4079 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4080 expect(LV_VIEW_ICON, ret);
4082 style = GetWindowLongPtr(hwnd, GWL_STYLE);
4083 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4084 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4085 expect(LV_VIEW_SMALLICON, ret);
4087 style = GetWindowLongPtr(hwnd, GWL_STYLE);
4088 SetWindowLongPtr(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4089 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4090 expect(LV_VIEW_LIST, ret);
4092 /* switching view doesn't touch window style */
4093 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4095 style = GetWindowLongPtr(hwnd, GWL_STYLE);
4096 ok(style & LVS_LIST, "Expected style to be preserved\n");
4097 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4099 style = GetWindowLongPtr(hwnd, GWL_STYLE);
4100 ok(style & LVS_LIST, "Expected style to be preserved\n");
4101 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4103 style = GetWindowLongPtr(hwnd, GWL_STYLE);
4104 ok(style & LVS_LIST, "Expected style to be preserved\n");
4106 DestroyWindow(hwnd);
4109 static void test_canceleditlabel(void)
4111 HWND hwnd, hwndedit;
4115 static CHAR test[] = "test";
4116 static const CHAR test1[] = "test1";
4118 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4119 ok(hwnd != NULL, "failed to create a listview window\n");
4121 insert_item(hwnd, 0);
4123 /* try without edit created */
4124 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4125 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4127 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4128 "cancel edit label without edit", FALSE);
4130 /* cancel without data change */
4132 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4133 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4134 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4136 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4138 /* cancel after data change */
4139 memset(&itema, 0, sizeof(itema));
4140 itema.pszText = test;
4141 ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
4144 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4145 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4146 ret = SetWindowText(hwndedit, test1);
4148 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4150 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4151 memset(&itema, 0, sizeof(itema));
4152 itema.pszText = buff;
4153 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
4154 ret = SendMessage(hwnd, LVM_GETITEMTEXT, 0, (LPARAM)&itema);
4156 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4158 DestroyWindow(hwnd);
4161 static void test_mapidindex(void)
4166 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4167 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4168 ok(hwnd != NULL, "failed to create a listview window\n");
4169 insert_item(hwnd, 0);
4170 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4172 DestroyWindow(hwnd);
4174 hwnd = create_listview_control(LVS_REPORT);
4175 ok(hwnd != NULL, "failed to create a listview window\n");
4177 /* LVM_MAPINDEXTOID with invalid index */
4178 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4181 insert_item(hwnd, 0);
4182 insert_item(hwnd, 1);
4184 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0);
4186 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0);
4189 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4191 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
4193 /* remove 0 indexed item, id retained */
4194 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
4195 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4197 /* new id starts from previous value */
4198 insert_item(hwnd, 1);
4199 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
4202 /* get index by id */
4203 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4205 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4207 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4209 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4212 DestroyWindow(hwnd);
4215 static void test_getitemspacing(void)
4224 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4225 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4228 hwnd = create_listview_control(LVS_ICON);
4229 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4231 expect(cx, LOWORD(ret));
4232 expect(cy, HIWORD(ret));
4234 /* now try with icons */
4235 himl = ImageList_Create(40, 40, 0, 4, 4);
4236 ok(himl != NULL, "failed to create imagelist\n");
4237 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4238 ok(hbmp != NULL, "failed to create bitmap\n");
4239 ret = ImageList_Add(himl, hbmp, 0);
4241 ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4244 itema.mask = LVIF_IMAGE;
4248 ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
4250 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4252 /* spacing + icon size returned */
4253 expect(cx + 40, LOWORD(ret));
4254 expect(cy + 40, HIWORD(ret));
4256 DestroyWindow(hwnd);
4258 hwnd = create_listview_control(LVS_SMALLICON);
4259 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4261 expect(cx, LOWORD(ret));
4262 expect(cy, HIWORD(ret));
4264 DestroyWindow(hwnd);
4266 hwnd = create_listview_control(LVS_REPORT);
4267 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4269 expect(cx, LOWORD(ret));
4270 expect(cy, HIWORD(ret));
4272 DestroyWindow(hwnd);
4274 hwnd = create_listview_control(LVS_LIST);
4275 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4277 expect(cx, LOWORD(ret));
4278 expect(cy, HIWORD(ret));
4280 DestroyWindow(hwnd);
4283 static void test_getcolumnwidth(void)
4292 /* default column width */
4293 hwnd = create_listview_control(LVS_ICON);
4294 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4296 style = GetWindowLong(hwnd, GWL_STYLE);
4297 SetWindowLong(hwnd, GWL_STYLE, style | LVS_LIST);
4298 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4299 todo_wine expect(8, ret);
4300 style = GetWindowLong(hwnd, GWL_STYLE) & ~LVS_LIST;
4301 SetWindowLong(hwnd, GWL_STYLE, style | LVS_REPORT);
4303 ret = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4305 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4307 DestroyWindow(hwnd);
4309 /* default column width with item added */
4310 hwnd = create_listview_control(LVS_LIST);
4311 memset(&itema, 0, sizeof(itema));
4312 SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4313 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4315 todo_wine expect(((GetDeviceCaps(hdc, LOGPIXELSX) + 15) / 16) * 16, ret);
4316 ReleaseDC(hwnd, hdc);
4317 DestroyWindow(hwnd);
4320 static void test_scrollnotify(void)
4325 hwnd = create_listview_control(LVS_REPORT);
4327 insert_column(hwnd, 0);
4328 insert_column(hwnd, 1);
4329 insert_item(hwnd, 0);
4331 /* make it scrollable - resize */
4332 ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4334 ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4337 /* try with dummy call */
4338 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4339 ret = SendMessage(hwnd, LVM_SCROLL, 0, 0);
4341 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4342 "scroll notify 1", TRUE);
4344 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4345 ret = SendMessage(hwnd, LVM_SCROLL, 1, 0);
4347 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4348 "scroll notify 2", TRUE);
4350 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4351 ret = SendMessage(hwnd, LVM_SCROLL, 1, 1);
4353 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4354 "scroll notify 3", TRUE);
4356 DestroyWindow(hwnd);
4359 static void test_LVS_EX_TRANSPARENTBKGND(void)
4365 hwnd = create_listview_control(LVS_REPORT);
4367 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4370 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4371 LVS_EX_TRANSPARENTBKGND);
4373 ret = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
4374 if (ret != CLR_NONE)
4376 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4377 DestroyWindow(hwnd);
4381 /* try to set some back color and check this style bit */
4382 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4384 ret = SendMessage(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4385 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4387 /* now test what this style actually does */
4388 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4389 LVS_EX_TRANSPARENTBKGND);
4391 hdc = GetWindowDC(hwndparent);
4393 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4394 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4395 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4396 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4398 ReleaseDC(hwndparent, hdc);
4400 DestroyWindow(hwnd);
4403 static void test_approximate_viewrect(void)
4410 static CHAR test[] = "abracadabra, a very long item label";
4412 hwnd = create_listview_control(LVS_ICON);
4413 himl = ImageList_Create(40, 40, 0, 4, 4);
4414 ok(himl != NULL, "failed to create imagelist\n");
4415 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4416 ok(hbmp != NULL, "failed to create bitmap\n");
4417 ret = ImageList_Add(himl, hbmp, 0);
4419 ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4422 itema.mask = LVIF_IMAGE;
4426 ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
4429 ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
4433 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
4437 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4438 expect(MAKELONG(77,827), ret);
4440 ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
4441 ok(ret != 0, "got 0\n");
4443 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4444 expect(MAKELONG(102,302), ret);
4446 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4447 expect(MAKELONG(52,52), ret);
4449 itema.pszText = test;
4450 ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
4452 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4453 expect(MAKELONG(52,52), ret);
4455 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
4456 expect(MAKELONG(52,2), ret);
4457 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
4458 expect(MAKELONG(52,52), ret);
4459 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
4460 expect(MAKELONG(102,52), ret);
4461 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
4462 expect(MAKELONG(102,102), ret);
4463 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
4464 expect(MAKELONG(102,102), ret);
4465 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
4466 expect(MAKELONG(102,152), ret);
4467 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
4468 expect(MAKELONG(102,152), ret);
4469 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
4470 expect(MAKELONG(152,152), ret);
4472 DestroyWindow(hwnd);
4475 static void test_finditem(void)
4482 hwnd = create_listview_control(LVS_REPORT);
4483 insert_item(hwnd, 0);
4485 memset(&fi, 0, sizeof(fi));
4487 /* full string search, inserted text was "foo" */
4489 fi.flags = LVFI_STRING;
4491 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4493 /* partial string search, inserted text was "foo" */
4495 fi.flags = LVFI_STRING | LVFI_PARTIAL;
4497 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4499 /* partial string search, part after start char */
4501 fi.flags = LVFI_STRING | LVFI_PARTIAL;
4503 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4506 /* try with LVFI_SUBSTRING */
4508 fi.flags = LVFI_SUBSTRING;
4510 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4513 win_skip("LVFI_SUBSTRING not supported\n");
4514 DestroyWindow(hwnd);
4519 fi.flags = LVFI_SUBSTRING;
4521 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4524 fi.flags = LVFI_SUBSTRING;
4526 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4530 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
4532 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4535 DestroyWindow(hwnd);
4538 static void test_LVS_EX_HEADERINALLVIEWS(void)
4543 hwnd = create_listview_control(LVS_ICON);
4545 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4546 LVS_EX_HEADERINALLVIEWS);
4548 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4549 if (!IsWindow(header))
4551 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
4552 DestroyWindow(hwnd);
4556 /* LVS_NOCOLUMNHEADER works as before */
4557 style = GetWindowLongA(hwnd, GWL_STYLE);
4558 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
4559 style = GetWindowLongA(header, GWL_STYLE);
4560 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
4561 style = GetWindowLongA(hwnd, GWL_STYLE);
4562 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
4563 style = GetWindowLongA(header, GWL_STYLE);
4564 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
4566 /* try to remove style */
4567 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
4568 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4569 ok(IsWindow(header), "Expected header to be created\n");
4570 style = GetWindowLongA(header, GWL_STYLE);
4571 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
4573 DestroyWindow(hwnd);
4575 /* check other styles */
4576 hwnd = create_listview_control(LVS_LIST);
4577 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4578 LVS_EX_HEADERINALLVIEWS);
4579 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4580 ok(IsWindow(header), "Expected header to be created\n");
4581 DestroyWindow(hwnd);
4583 hwnd = create_listview_control(LVS_SMALLICON);
4584 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4585 LVS_EX_HEADERINALLVIEWS);
4586 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4587 ok(IsWindow(header), "Expected header to be created\n");
4588 DestroyWindow(hwnd);
4590 hwnd = create_listview_control(LVS_REPORT);
4591 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4592 LVS_EX_HEADERINALLVIEWS);
4593 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4594 ok(IsWindow(header), "Expected header to be created\n");
4595 DestroyWindow(hwnd);
4598 static void test_hover(void)
4603 hwnd = create_listview_control(LVS_ICON);
4605 /* test WM_MOUSEHOVER forwarding */
4606 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4607 r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
4609 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
4610 g_block_hover = TRUE;
4611 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4612 r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
4614 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
4615 g_block_hover = FALSE;
4617 r = SendMessage(hwnd, LVM_SETHOVERTIME, 0, 500);
4618 expect(HOVER_DEFAULT, r);
4619 r = SendMessage(hwnd, LVM_GETHOVERTIME, 0, 0);
4622 DestroyWindow(hwnd);
4625 static void test_destroynotify(void)
4629 hwnd = create_listview_control(LVS_REPORT);
4630 ok(hwnd != NULL, "failed to create listview window\n");
4632 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4633 DestroyWindow(hwnd);
4634 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
4637 static void test_header_notification(void)
4639 static char textA[] = "newtext";
4647 list = create_listview_control(LVS_REPORT);
4648 ok(list != NULL, "failed to create listview window\n");
4650 memset(&col, 0, sizeof(col));
4651 col.mask = LVCF_WIDTH;
4653 ret = SendMessage(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4656 /* check list parent notification after header item changed,
4657 this test should be placed before header subclassing to avoid
4658 Listview -> Header messages to be logged */
4659 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4661 col.mask = LVCF_TEXT;
4662 col.pszText = textA;
4663 r = SendMessage(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
4666 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
4667 "header notify, listview", FALSE);
4668 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4669 "header notify, parent", FALSE);
4671 header = subclass_header(list);
4673 ret = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
4676 memset(&item, 0, sizeof(item));
4677 item.mask = HDI_WIDTH;
4678 ret = SendMessage(header, HDM_GETITEMA, 0, (LPARAM)&item);
4680 expect(100, item.cxy);
4682 nmh.hdr.hwndFrom = header;
4683 nmh.hdr.idFrom = GetWindowLongPtr(header, GWLP_ID);
4684 nmh.hdr.code = HDN_ITEMCHANGEDA;
4687 item.mask = HDI_WIDTH;
4690 ret = SendMessage(list, WM_NOTIFY, 0, (LPARAM)&nmh);
4693 DestroyWindow(list);
4696 static void test_createdragimage(void)
4702 list = create_listview_control(LVS_ICON);
4703 ok(list != NULL, "failed to create listview window\n");
4705 insert_item(list, 0);
4708 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
4709 ok(himl == NULL, "got %p\n", himl);
4711 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
4712 ok(himl != NULL, "got %p\n", himl);
4713 ImageList_Destroy(himl);
4715 DestroyWindow(list);
4718 static void test_dispinfo(void)
4720 static const char testA[] = "TEST";
4726 hwnd = create_listview_control(LVS_ICON);
4727 ok(hwnd != NULL, "failed to create listview window\n");
4729 insert_item(hwnd, 0);
4731 memset(&item, 0, sizeof(item));
4732 item.pszText = LPSTR_TEXTCALLBACKA;
4733 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4736 g_disp_A_to_W = TRUE;
4737 item.pszText = (char*)buff;
4738 item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
4739 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4740 ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
4741 g_disp_A_to_W = FALSE;
4743 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
4744 "got %s, expected %s\n", item.pszText, testA);
4746 DestroyWindow(hwnd);
4749 static void test_LVM_SETITEMTEXT(void)
4751 static char testA[] = "TEST";
4756 hwnd = create_listview_control(LVS_ICON);
4757 ok(hwnd != NULL, "failed to create listview window\n");
4759 insert_item(hwnd, 0);
4761 /* null item pointer */
4762 ret = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, 0);
4765 ret = SendMessage(hwnd, LVM_SETITEMTEXTW, 0, 0);
4768 /* index out of bounds */
4769 item.pszText = testA;
4770 item.cchTextMax = 0; /* ignored */
4773 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
4776 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
4779 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4782 DestroyWindow(hwnd);
4785 START_TEST(listview)
4788 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
4790 ULONG_PTR ctx_cookie;
4794 hComctl32 = GetModuleHandleA("comctl32.dll");
4795 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
4796 if (pInitCommonControlsEx)
4798 INITCOMMONCONTROLSEX iccex;
4799 iccex.dwSize = sizeof(iccex);
4800 iccex.dwICC = ICC_LISTVIEW_CLASSES;
4801 pInitCommonControlsEx(&iccex);
4804 InitCommonControls();
4806 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
4808 hwndparent = create_parent_window(FALSE);
4809 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4811 g_is_below_5 = is_below_comctl_5();
4813 test_header_notification();
4820 test_icon_spacing();
4823 test_item_position();
4828 test_subitem_rect();
4832 test_nosortheader();
4836 test_getitemposition();
4837 test_columnscreation();
4839 test_notifyformat();
4841 test_getitemspacing();
4842 test_getcolumnwidth();
4843 test_approximate_viewrect();
4846 test_destroynotify();
4847 test_createdragimage();
4849 test_LVM_SETITEMTEXT();
4851 if (!load_v6_module(&ctx_cookie, &hCtx))
4853 DestroyWindow(hwndparent);
4857 /* this is a XP SP3 failure workaround */
4858 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
4859 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
4861 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
4862 if (!IsWindow(hwnd))
4864 win_skip("FIXME: failed to create ListView window.\n");
4865 unload_v6_module(ctx_cookie, hCtx);
4866 DestroyWindow(hwndparent);
4870 DestroyWindow(hwnd);
4872 /* comctl32 version 6 tests start here */
4873 test_get_set_view();
4874 test_canceleditlabel();
4876 test_scrollnotify();
4877 test_LVS_EX_TRANSPARENTBKGND();
4878 test_LVS_EX_HEADERINALLVIEWS();
4880 unload_v6_module(ctx_cookie, hCtx);
4882 DestroyWindow(hwndparent);