ddraw: Return early in d3d_device7_DrawIndexedPrimitiveStrided() with a 0 vertex...
[wine.git] / dlls / comctl32 / tests / listview.c
blob10e7d0e83b377e483657080d0ad8d19d4dce5fbd
1 /*
2 * ListView tests
4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * Copyright 2009-2014 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdio.h>
24 #include <windows.h>
25 #include <commctrl.h>
27 #include "wine/test.h"
28 #include "v6util.h"
29 #include "msg.h"
31 enum seq_index {
32 PARENT_SEQ_INDEX,
33 PARENT_FULL_SEQ_INDEX,
34 PARENT_CD_SEQ_INDEX,
35 LISTVIEW_SEQ_INDEX,
36 EDITBOX_SEQ_INDEX,
37 COMBINED_SEQ_INDEX,
38 NUM_MSG_SEQUENCES
41 #define LISTVIEW_ID 0
42 #define HEADER_ID 1
44 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
45 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
46 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
48 static const WCHAR testparentclassW[] =
49 {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
51 static HWND hwndparent, hwndparentW;
52 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
53 static BOOL blockEdit;
54 /* return nonzero on NM_HOVER */
55 static BOOL g_block_hover;
56 /* notification data for LVN_ITEMCHANGED */
57 static NMLISTVIEW g_nmlistview;
58 /* notification data for LVN_ITEMCHANGING */
59 static NMLISTVIEW g_nmlistview_changing;
60 /* format reported to control:
61 -1 falls to defproc, anything else returned */
62 static INT notifyFormat;
63 /* indicates we're running < 5.80 version */
64 static BOOL g_is_below_5;
65 /* item data passed to LVN_GETDISPINFOA */
66 static LVITEMA g_itema;
67 /* alter notification code A->W */
68 static BOOL g_disp_A_to_W;
69 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
70 static NMLVDISPINFOA g_editbox_disp_info;
71 /* when this is set focus will be tested on LVN_DELETEITEM */
72 static BOOL g_focus_test_LVN_DELETEITEM;
74 static HWND subclass_editbox(HWND hwndListview);
76 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
78 static const struct message create_ownerdrawfixed_parent_seq[] = {
79 { WM_NOTIFYFORMAT, sent },
80 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
81 { WM_MEASUREITEM, sent },
82 { WM_PARENTNOTIFY, sent },
83 { 0 }
86 static const struct message redraw_listview_seq[] = {
87 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
88 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
89 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
90 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
91 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
92 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
93 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
94 { 0 }
97 static const struct message listview_icon_spacing_seq[] = {
98 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
99 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
100 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
101 { 0 }
104 static const struct message listview_color_seq[] = {
105 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
106 { LVM_GETBKCOLOR, sent },
107 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
108 { LVM_GETTEXTCOLOR, sent },
109 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
110 { LVM_GETTEXTBKCOLOR, sent },
112 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
113 { LVM_GETBKCOLOR, sent },
114 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
115 { LVM_GETTEXTCOLOR, sent },
116 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
117 { LVM_GETTEXTBKCOLOR, sent },
119 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
120 { LVM_GETBKCOLOR, sent },
121 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
122 { LVM_GETTEXTCOLOR, sent },
123 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
124 { LVM_GETTEXTBKCOLOR, sent },
126 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
127 { LVM_GETBKCOLOR, sent },
128 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
129 { LVM_GETTEXTCOLOR, sent },
130 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
131 { LVM_GETTEXTBKCOLOR, sent },
132 { 0 }
135 static const struct message listview_item_count_seq[] = {
136 { LVM_GETITEMCOUNT, sent },
137 { LVM_INSERTITEMA, sent },
138 { LVM_INSERTITEMA, sent },
139 { LVM_INSERTITEMA, sent },
140 { LVM_GETITEMCOUNT, sent },
141 { LVM_DELETEITEM, sent|wparam, 2 },
142 { WM_NCPAINT, sent|optional },
143 { WM_ERASEBKGND, sent|optional },
144 { LVM_GETITEMCOUNT, sent },
145 { LVM_DELETEALLITEMS, sent },
146 { LVM_GETITEMCOUNT, sent },
147 { LVM_INSERTITEMA, sent },
148 { LVM_INSERTITEMA, sent },
149 { LVM_GETITEMCOUNT, sent },
150 { LVM_INSERTITEMA, sent },
151 { LVM_GETITEMCOUNT, sent },
152 { 0 }
155 static const struct message listview_itempos_seq[] = {
156 { LVM_INSERTITEMA, sent },
157 { LVM_INSERTITEMA, sent },
158 { LVM_INSERTITEMA, sent },
159 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
160 { WM_NCPAINT, sent|optional },
161 { WM_ERASEBKGND, sent|optional },
162 { LVM_GETITEMPOSITION, sent|wparam, 1 },
163 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
164 { LVM_GETITEMPOSITION, sent|wparam, 2 },
165 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
166 { LVM_GETITEMPOSITION, sent|wparam, 0 },
167 { 0 }
170 static const struct message listview_ownerdata_switchto_seq[] = {
171 { WM_STYLECHANGING, sent },
172 { WM_STYLECHANGED, sent },
173 { 0 }
176 static const struct message listview_getorderarray_seq[] = {
177 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
178 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
179 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
180 { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
181 { 0 }
184 static const struct message listview_setorderarray_seq[] = {
185 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
186 { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
187 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
188 { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
189 { 0 }
192 static const struct message empty_seq[] = {
193 { 0 }
196 static const struct message forward_erasebkgnd_parent_seq[] = {
197 { WM_ERASEBKGND, sent },
198 { 0 }
201 static const struct message ownerdata_select_focus_parent_seq[] = {
202 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
203 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
204 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
205 { 0 }
208 static const struct message ownerdata_setstate_all_parent_seq[] = {
209 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
210 { 0 }
213 static const struct message ownerdata_defocus_all_parent_seq[] = {
214 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
215 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
216 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
217 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
218 { 0 }
221 static const struct message ownerdata_deselect_all_parent_seq[] = {
222 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
223 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
224 { 0 }
227 static const struct message change_all_parent_seq[] = {
228 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
229 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
231 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
232 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
234 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
235 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
237 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
238 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
240 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
241 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
242 { 0 }
245 static const struct message changing_all_parent_seq[] = {
246 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
247 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
248 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
249 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
250 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
251 { 0 }
254 static const struct message textcallback_set_again_parent_seq[] = {
255 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
256 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
257 { 0 }
260 static const struct message single_getdispinfo_parent_seq[] = {
261 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
262 { 0 }
265 static const struct message getitemposition_seq1[] = {
266 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
267 { 0 }
270 static const struct message getitemposition_seq2[] = {
271 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
272 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
273 { 0 }
276 static const struct message getsubitemrect_seq[] = {
277 { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
278 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
279 { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
280 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
281 { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
282 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
283 { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
284 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
285 { 0 }
288 static const struct message editbox_create_pos[] = {
289 /* sequence sent after LVN_BEGINLABELEDIT */
290 /* next two are 4.7x specific */
291 { WM_WINDOWPOSCHANGING, sent },
292 { WM_WINDOWPOSCHANGED, sent|optional },
294 { WM_WINDOWPOSCHANGING, sent|optional },
295 { WM_NCCALCSIZE, sent },
296 { WM_WINDOWPOSCHANGED, sent },
297 { WM_MOVE, sent|defwinproc },
298 { WM_SIZE, sent|defwinproc },
299 /* the rest is todo, skipped in 4.7x */
300 { WM_WINDOWPOSCHANGING, sent|optional },
301 { WM_WINDOWPOSCHANGED, sent|optional },
302 { 0 }
305 static const struct message scroll_parent_seq[] = {
306 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
307 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
308 { 0 }
311 static const struct message setredraw_seq[] = {
312 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
313 { 0 }
316 static const struct message lvs_ex_transparentbkgnd_seq[] = {
317 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
318 { 0 }
321 static const struct message edit_end_nochange[] = {
322 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
323 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
324 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
325 { 0 }
328 static const struct message hover_parent[] = {
329 { WM_GETDLGCODE, sent }, /* todo_wine */
330 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
331 { 0 }
334 static const struct message listview_destroy[] = {
335 { 0x0090, sent|optional }, /* Vista */
336 { WM_PARENTNOTIFY, sent },
337 { WM_SHOWWINDOW, sent },
338 { WM_WINDOWPOSCHANGING, sent },
339 { WM_WINDOWPOSCHANGED, sent|optional },
340 { WM_DESTROY, sent },
341 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
342 { WM_NCDESTROY, sent },
343 { 0 }
346 static const struct message listview_ownerdata_destroy[] = {
347 { 0x0090, sent|optional }, /* Vista */
348 { WM_PARENTNOTIFY, sent },
349 { WM_SHOWWINDOW, sent },
350 { WM_WINDOWPOSCHANGING, sent },
351 { WM_WINDOWPOSCHANGED, sent|optional },
352 { WM_DESTROY, sent },
353 { WM_NCDESTROY, sent },
354 { 0 }
357 static const struct message listview_ownerdata_deleteall[] = {
358 { LVM_DELETEALLITEMS, sent },
359 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
360 { 0 }
363 static const struct message listview_header_changed_seq[] = {
364 { LVM_SETCOLUMNA, sent },
365 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
366 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
367 { 0 }
370 static const struct message parent_header_click_seq[] = {
371 { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
372 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
373 { 0 }
376 static const struct message parent_header_divider_dclick_seq[] = {
377 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
378 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
379 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
380 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
381 { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
382 { 0 }
385 static const struct message listview_set_imagelist[] = {
386 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
387 { 0 }
390 static const struct message listview_header_set_imagelist[] = {
391 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
392 { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
393 { 0 }
396 static const struct message parent_insert_focused_seq[] = {
397 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
398 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
399 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
400 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
401 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
402 { 0 }
405 static const struct message parent_report_cd_seq[] = {
406 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
407 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
408 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
409 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
410 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
411 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
412 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
413 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
414 { 0 }
417 static const struct message parent_list_cd_seq[] = {
418 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
419 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
420 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
421 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
422 { 0 }
425 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
427 static LONG defwndproc_counter = 0;
428 LRESULT ret;
429 struct message msg;
431 msg.message = message;
432 msg.flags = sent|wparam|lparam;
433 if (defwndproc_counter) msg.flags |= defwinproc;
434 msg.wParam = wParam;
435 msg.lParam = lParam;
436 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
438 /* log system messages, except for painting */
439 if (message < WM_USER &&
440 message != WM_PAINT &&
441 message != WM_ERASEBKGND &&
442 message != WM_NCPAINT &&
443 message != WM_NCHITTEST &&
444 message != WM_GETTEXT &&
445 message != WM_GETICON &&
446 message != WM_DEVICECHANGE)
448 add_message(sequences, PARENT_SEQ_INDEX, &msg);
449 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
451 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
453 switch (message)
455 case WM_NOTIFY:
457 switch (((NMHDR*)lParam)->code)
459 case LVN_BEGINLABELEDITA:
461 HWND edit = NULL;
463 /* subclass edit box */
464 if (!blockEdit)
465 edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
467 if (edit)
469 INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
470 ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
471 "text limit %d, expected 259\n", len);
474 return blockEdit;
476 case LVN_ENDLABELEDITA:
478 HWND edit;
480 /* always accept new item text */
481 NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
482 g_editbox_disp_info = *di;
483 trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText ? di->item.pszText : "(null)");
485 /* edit control still available from this notification */
486 edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
487 ok(IsWindow(edit), "expected valid edit control handle\n");
488 ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
490 return TRUE;
492 case LVN_BEGINSCROLL:
493 case LVN_ENDSCROLL:
495 NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
497 trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
498 "BEGIN" : "END", pScroll->dx, pScroll->dy);
500 break;
501 case LVN_ITEMCHANGING:
503 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
504 g_nmlistview_changing = *nmlv;
506 break;
507 case LVN_ITEMCHANGED:
509 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
510 g_nmlistview = *nmlv;
512 break;
513 case LVN_GETDISPINFOA:
515 NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
516 g_itema = dispinfo->item;
518 if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
520 static const WCHAR testW[] = {'T','E','S','T',0};
521 dispinfo->hdr.code = LVN_GETDISPINFOW;
522 memcpy(dispinfo->item.pszText, testW, sizeof(testW));
525 /* test control buffer size for text, 10 used to mask cases when control
526 is using caller buffer to process LVM_GETITEM for example */
527 if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
528 ok(dispinfo->item.cchTextMax == 260 ||
529 broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
530 "buffer size %d\n", dispinfo->item.cchTextMax);
532 break;
533 case LVN_DELETEITEM:
534 if (g_focus_test_LVN_DELETEITEM)
536 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
537 UINT state;
539 state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
540 ok(state == 0, "got state %x\n", state);
542 break;
543 case NM_HOVER:
544 if (g_block_hover) return 1;
545 break;
547 break;
549 case WM_NOTIFYFORMAT:
551 /* force to return format */
552 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
553 break;
557 defwndproc_counter++;
558 ret = DefWindowProcA(hwnd, message, wParam, lParam);
559 defwndproc_counter--;
561 return ret;
564 static BOOL register_parent_wnd_class(BOOL Unicode)
566 WNDCLASSA clsA;
567 WNDCLASSW clsW;
569 if (Unicode)
571 clsW.style = 0;
572 clsW.lpfnWndProc = parent_wnd_proc;
573 clsW.cbClsExtra = 0;
574 clsW.cbWndExtra = 0;
575 clsW.hInstance = GetModuleHandleW(NULL);
576 clsW.hIcon = 0;
577 clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
578 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
579 clsW.lpszMenuName = NULL;
580 clsW.lpszClassName = testparentclassW;
582 else
584 clsA.style = 0;
585 clsA.lpfnWndProc = parent_wnd_proc;
586 clsA.cbClsExtra = 0;
587 clsA.cbWndExtra = 0;
588 clsA.hInstance = GetModuleHandleA(NULL);
589 clsA.hIcon = 0;
590 clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
591 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
592 clsA.lpszMenuName = NULL;
593 clsA.lpszClassName = "Listview test parent class";
596 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
599 static HWND create_parent_window(BOOL Unicode)
601 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
602 HWND hwnd;
604 if (!register_parent_wnd_class(Unicode))
605 return NULL;
607 blockEdit = FALSE;
608 notifyFormat = -1;
610 if (Unicode)
611 hwnd = CreateWindowExW(0, testparentclassW, nameW,
612 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
613 WS_MAXIMIZEBOX | WS_VISIBLE,
614 0, 0, 100, 100,
615 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
616 else
617 hwnd = CreateWindowExA(0, "Listview test parent class",
618 "Listview test parent window",
619 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
620 WS_MAXIMIZEBOX | WS_VISIBLE,
621 0, 0, 100, 100,
622 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
623 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
624 return hwnd;
627 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
629 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
630 static LONG defwndproc_counter = 0;
631 LRESULT ret;
632 struct message msg;
634 /* some debug output for style changing */
635 if ((message == WM_STYLECHANGING ||
636 message == WM_STYLECHANGED) && lParam)
638 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
639 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
642 msg.message = message;
643 msg.flags = sent|wparam|lparam;
644 if (defwndproc_counter) msg.flags |= defwinproc;
645 msg.wParam = wParam;
646 msg.lParam = lParam;
647 msg.id = LISTVIEW_ID;
648 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
649 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
651 defwndproc_counter++;
652 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
653 defwndproc_counter--;
654 return ret;
657 static HWND create_listview_control(DWORD style)
659 WNDPROC oldproc;
660 HWND hwnd;
661 RECT rect;
663 GetClientRect(hwndparent, &rect);
664 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
665 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
666 0, 0, rect.right, rect.bottom,
667 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
668 ok(hwnd != NULL, "gle=%d\n", GetLastError());
670 if (!hwnd) return NULL;
672 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
673 (LONG_PTR)listview_subclass_proc);
674 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
676 return hwnd;
679 /* unicode listview window with specified parent */
680 static HWND create_listview_controlW(DWORD style, HWND parent)
682 WNDPROC oldproc;
683 HWND hwnd;
684 RECT rect;
685 static const WCHAR nameW[] = {'f','o','o',0};
687 GetClientRect(parent, &rect);
688 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
689 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
690 0, 0, rect.right, rect.bottom,
691 parent, NULL, GetModuleHandleW(NULL), NULL);
692 ok(hwnd != NULL, "gle=%d\n", GetLastError());
694 if (!hwnd) return NULL;
696 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
697 (LONG_PTR)listview_subclass_proc);
698 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
700 return hwnd;
703 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
705 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
706 static LONG defwndproc_counter = 0;
707 LRESULT ret;
708 struct message msg;
710 msg.message = message;
711 msg.flags = sent|wparam|lparam;
712 if (defwndproc_counter) msg.flags |= defwinproc;
713 msg.wParam = wParam;
714 msg.lParam = lParam;
715 msg.id = HEADER_ID;
716 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
718 defwndproc_counter++;
719 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
720 defwndproc_counter--;
721 return ret;
724 static HWND subclass_header(HWND hwndListview)
726 WNDPROC oldproc;
727 HWND hwnd;
729 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
730 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
731 (LONG_PTR)header_subclass_proc);
732 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
734 return hwnd;
737 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
739 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
740 static LONG defwndproc_counter = 0;
741 LRESULT ret;
742 struct message msg;
744 msg.message = message;
745 msg.flags = sent|wparam|lparam;
746 if (defwndproc_counter) msg.flags |= defwinproc;
747 msg.wParam = wParam;
748 msg.lParam = lParam;
749 msg.id = 0;
751 /* all we need is sizing */
752 if (message == WM_WINDOWPOSCHANGING ||
753 message == WM_NCCALCSIZE ||
754 message == WM_WINDOWPOSCHANGED ||
755 message == WM_MOVE ||
756 message == WM_SIZE)
758 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
761 defwndproc_counter++;
762 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
763 defwndproc_counter--;
764 return ret;
767 static HWND subclass_editbox(HWND hwndListview)
769 WNDPROC oldproc;
770 HWND hwnd;
772 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
773 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
774 (LONG_PTR)editbox_subclass_proc);
775 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
777 return hwnd;
780 /* Performs a single LVM_HITTEST test */
781 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
782 BOOL todo_item, BOOL todo_flags, int line)
784 LVHITTESTINFO lpht;
785 INT ret;
787 lpht.pt.x = x;
788 lpht.pt.y = y;
789 lpht.iSubItem = 10;
791 ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
793 todo_wine_if(todo_item)
795 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
796 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
797 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
800 if (todo_flags)
802 todo_wine
803 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
805 else if (broken_flags)
806 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
807 "Expected flags %x, got %x\n", flags, lpht.flags);
808 else
809 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
812 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
814 /* Performs a single LVM_SUBITEMHITTEST test */
815 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
816 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
818 LVHITTESTINFO lpht;
819 INT ret;
821 lpht.pt.x = x;
822 lpht.pt.y = y;
824 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
826 todo_wine_if(todo_item)
828 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
829 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
832 todo_wine_if(todo_subitem)
833 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
835 todo_wine_if(todo_flags)
836 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
839 #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__)
841 static void test_images(void)
843 HWND hwnd;
844 INT r;
845 LVITEMA item;
846 HIMAGELIST himl;
847 HBITMAP hbmp;
848 RECT r1, r2;
849 static CHAR hello[] = "hello";
851 himl = ImageList_Create(40, 40, 0, 4, 4);
852 ok(himl != NULL, "failed to create imagelist\n");
854 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
855 ok(hbmp != NULL, "failed to create bitmap\n");
857 r = ImageList_Add(himl, hbmp, 0);
858 ok(r == 0, "should be zero\n");
860 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
861 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
862 ok(hwnd != NULL, "failed to create listview window\n");
864 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
865 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
867 ok(r == 0, "should return zero\n");
869 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
870 ok(r == 0, "should return zero\n");
872 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
873 ok(r != 0, "got 0\n");
875 /* returns dimensions */
877 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
878 ok(r == 0, "should be zero items\n");
880 item.mask = LVIF_IMAGE | LVIF_TEXT;
881 item.iItem = 0;
882 item.iSubItem = 1;
883 item.iImage = 0;
884 item.pszText = 0;
885 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
886 ok(r == -1, "should fail\n");
888 item.iSubItem = 0;
889 item.pszText = hello;
890 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
891 ok(r == 0, "should not fail\n");
893 memset(&r1, 0, sizeof r1);
894 r1.left = LVIR_ICON;
895 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
896 expect(1, r);
898 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
899 ok(r == TRUE, "should not fail\n");
901 item.iSubItem = 0;
902 item.pszText = hello;
903 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
904 ok(r == 0, "should not fail\n");
906 memset(&r2, 0, sizeof r2);
907 r2.left = LVIR_ICON;
908 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
909 expect(1, r);
911 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
913 DestroyWindow(hwnd);
916 static void test_checkboxes(void)
918 HWND hwnd;
919 LVITEMA item;
920 DWORD r;
921 static CHAR text[] = "Text",
922 text2[] = "Text2",
923 text3[] = "Text3";
925 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
926 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
927 ok(hwnd != NULL, "failed to create listview window\n");
929 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
930 item.mask = LVIF_TEXT | LVIF_STATE;
931 item.stateMask = 0xffff;
932 item.state = 0xfccc;
933 item.iItem = 0;
934 item.iSubItem = 0;
935 item.pszText = text;
936 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
937 expect(0, r);
939 item.iItem = 0;
940 item.mask = LVIF_STATE;
941 item.stateMask = 0xffff;
942 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
943 expect(1, r);
944 ok(item.state == 0xfccc, "state %x\n", item.state);
946 /* Don't set LVIF_STATE */
947 item.mask = LVIF_TEXT;
948 item.stateMask = 0xffff;
949 item.state = 0xfccc;
950 item.iItem = 1;
951 item.iSubItem = 0;
952 item.pszText = text;
953 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
954 expect(1, r);
956 item.iItem = 1;
957 item.mask = LVIF_STATE;
958 item.stateMask = 0xffff;
959 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
960 expect(1, r);
961 ok(item.state == 0, "state %x\n", item.state);
963 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
964 expect(0, r);
966 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
967 item.iItem = 0;
968 item.mask = LVIF_STATE;
969 item.stateMask = 0xffff;
970 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
971 expect(1, r);
972 if (item.state != 0x1ccc)
974 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
975 DestroyWindow(hwnd);
976 return;
979 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
980 item.iItem = 2;
981 item.mask = LVIF_TEXT;
982 item.state = 0;
983 item.pszText = text2;
984 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
985 expect(2, r);
987 item.iItem = 2;
988 item.mask = LVIF_STATE;
989 item.stateMask = 0xffff;
990 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
991 expect(1, r);
992 ok(item.state == 0x1000, "state %x\n", item.state);
994 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
995 item.iItem = 3;
996 item.mask = LVIF_TEXT | LVIF_STATE;
997 item.stateMask = 0xffff;
998 item.state = 0x2aaa;
999 item.pszText = text3;
1000 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1001 expect(3, r);
1003 item.iItem = 3;
1004 item.mask = LVIF_STATE;
1005 item.stateMask = 0xffff;
1006 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1007 expect(1, r);
1008 ok(item.state == 0x1aaa, "state %x\n", item.state);
1010 /* Set an item's state to checked */
1011 item.iItem = 3;
1012 item.mask = LVIF_STATE;
1013 item.stateMask = 0xf000;
1014 item.state = 0x2000;
1015 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1016 expect(1, r);
1018 item.iItem = 3;
1019 item.mask = LVIF_STATE;
1020 item.stateMask = 0xffff;
1021 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1022 expect(1, r);
1023 ok(item.state == 0x2aaa, "state %x\n", item.state);
1025 /* Check that only the bits we asked for are returned,
1026 * and that all the others are set to zero
1028 item.iItem = 3;
1029 item.mask = LVIF_STATE;
1030 item.stateMask = 0xf000;
1031 item.state = 0xffff;
1032 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1033 expect(1, r);
1034 ok(item.state == 0x2000, "state %x\n", item.state);
1036 /* Set the style again and check that doesn't change an item's state */
1037 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1038 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1040 item.iItem = 3;
1041 item.mask = LVIF_STATE;
1042 item.stateMask = 0xffff;
1043 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1044 expect(1, r);
1045 ok(item.state == 0x2aaa, "state %x\n", item.state);
1047 /* Unsetting the checkbox extended style doesn't change an item's state */
1048 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1049 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1051 item.iItem = 3;
1052 item.mask = LVIF_STATE;
1053 item.stateMask = 0xffff;
1054 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1055 expect(1, r);
1056 ok(item.state == 0x2aaa, "state %x\n", item.state);
1058 /* Now setting the style again will change an item's state */
1059 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1060 expect(0, r);
1062 item.iItem = 3;
1063 item.mask = LVIF_STATE;
1064 item.stateMask = 0xffff;
1065 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1066 expect(1, r);
1067 ok(item.state == 0x1aaa, "state %x\n", item.state);
1069 /* Toggle checkbox tests (bug 9934) */
1070 memset (&item, 0xcc, sizeof(item));
1071 item.mask = LVIF_STATE;
1072 item.iItem = 3;
1073 item.iSubItem = 0;
1074 item.state = LVIS_FOCUSED;
1075 item.stateMask = LVIS_FOCUSED;
1076 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1077 expect(1, r);
1079 item.iItem = 3;
1080 item.mask = LVIF_STATE;
1081 item.stateMask = 0xffff;
1082 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1083 expect(1, r);
1084 ok(item.state == 0x1aab, "state %x\n", item.state);
1086 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1087 expect(0, r);
1088 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1089 expect(0, r);
1091 item.iItem = 3;
1092 item.mask = LVIF_STATE;
1093 item.stateMask = 0xffff;
1094 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1095 expect(1, r);
1096 ok(item.state == 0x2aab, "state %x\n", item.state);
1098 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1099 expect(0, r);
1100 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1101 expect(0, r);
1103 item.iItem = 3;
1104 item.mask = LVIF_STATE;
1105 item.stateMask = 0xffff;
1106 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1107 expect(1, r);
1108 ok(item.state == 0x1aab, "state %x\n", item.state);
1110 DestroyWindow(hwnd);
1113 static void insert_column(HWND hwnd, int idx)
1115 LVCOLUMNA column;
1116 INT rc;
1118 memset(&column, 0xcc, sizeof(column));
1119 column.mask = LVCF_SUBITEM;
1120 column.iSubItem = idx;
1122 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1123 expect(idx, rc);
1126 static void insert_item(HWND hwnd, int idx)
1128 static CHAR text[] = "foo";
1130 LVITEMA item;
1131 INT rc;
1133 memset(&item, 0xcc, sizeof (item));
1134 item.mask = LVIF_TEXT;
1135 item.iItem = idx;
1136 item.iSubItem = 0;
1137 item.pszText = text;
1139 rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1140 expect(idx, rc);
1143 static void test_items(void)
1145 const LPARAM lparamTest = 0x42;
1146 static CHAR text[] = "Text";
1147 char buffA[5];
1148 HWND hwnd;
1149 LVITEMA item;
1150 DWORD r;
1152 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1153 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1154 ok(hwnd != NULL, "failed to create listview window\n");
1157 * Test setting/getting item params
1160 /* Set up two columns */
1161 insert_column(hwnd, 0);
1162 insert_column(hwnd, 1);
1164 /* LVIS_SELECTED with zero stateMask */
1165 /* set */
1166 memset (&item, 0, sizeof (item));
1167 item.mask = LVIF_STATE;
1168 item.state = LVIS_SELECTED;
1169 item.stateMask = 0;
1170 item.iItem = 0;
1171 item.iSubItem = 0;
1172 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1173 expect(0, r);
1174 /* get */
1175 memset (&item, 0xcc, sizeof (item));
1176 item.mask = LVIF_STATE;
1177 item.stateMask = LVIS_SELECTED;
1178 item.state = 0;
1179 item.iItem = 0;
1180 item.iSubItem = 0;
1181 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1182 expect(1, r);
1183 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1184 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1186 /* LVIS_SELECTED with zero stateMask */
1187 /* set */
1188 memset (&item, 0, sizeof (item));
1189 item.mask = LVIF_STATE;
1190 item.state = LVIS_FOCUSED;
1191 item.stateMask = 0;
1192 item.iItem = 0;
1193 item.iSubItem = 0;
1194 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1195 expect(0, r);
1196 /* get */
1197 memset (&item, 0xcc, sizeof (item));
1198 item.mask = LVIF_STATE;
1199 item.stateMask = LVIS_FOCUSED;
1200 item.state = 0;
1201 item.iItem = 0;
1202 item.iSubItem = 0;
1203 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1204 expect(1, r);
1205 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1206 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1208 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1209 /* set */
1210 memset (&item, 0, sizeof (item));
1211 item.mask = LVIF_STATE;
1212 item.state = LVIS_CUT;
1213 item.stateMask = LVIS_FOCUSED;
1214 item.iItem = 0;
1215 item.iSubItem = 0;
1216 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1217 expect(0, r);
1218 /* get */
1219 memset (&item, 0xcc, sizeof (item));
1220 item.mask = LVIF_STATE;
1221 item.stateMask = LVIS_CUT;
1222 item.state = 0;
1223 item.iItem = 0;
1224 item.iSubItem = 0;
1225 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1226 expect(1, r);
1227 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1228 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1230 /* Insert an item with just a param */
1231 memset (&item, 0xcc, sizeof (item));
1232 item.mask = LVIF_PARAM;
1233 item.iItem = 0;
1234 item.iSubItem = 0;
1235 item.lParam = lparamTest;
1236 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1237 expect(0, r);
1239 /* Test getting of the param */
1240 memset (&item, 0xcc, sizeof (item));
1241 item.mask = LVIF_PARAM;
1242 item.iItem = 0;
1243 item.iSubItem = 0;
1244 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1245 expect(1, r);
1246 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1248 /* Set up a subitem */
1249 memset (&item, 0xcc, sizeof (item));
1250 item.mask = LVIF_TEXT;
1251 item.iItem = 0;
1252 item.iSubItem = 1;
1253 item.pszText = text;
1254 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1255 expect(1, r);
1257 item.mask = LVIF_TEXT;
1258 item.iItem = 0;
1259 item.iSubItem = 1;
1260 item.pszText = buffA;
1261 item.cchTextMax = sizeof(buffA);
1262 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1263 expect(1, r);
1264 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1266 /* set up with extra flag */
1267 /* 1. reset subitem text */
1268 item.mask = LVIF_TEXT;
1269 item.iItem = 0;
1270 item.iSubItem = 1;
1271 item.pszText = NULL;
1272 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1273 expect(1, r);
1275 item.mask = LVIF_TEXT;
1276 item.iItem = 0;
1277 item.iSubItem = 1;
1278 item.pszText = buffA;
1279 buffA[0] = 'a';
1280 item.cchTextMax = sizeof(buffA);
1281 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1282 expect(1, r);
1283 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1285 /* 2. set new text with extra flag specified */
1286 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1287 item.iItem = 0;
1288 item.iSubItem = 1;
1289 item.pszText = text;
1290 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1291 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1293 if (r == 1)
1295 item.mask = LVIF_TEXT;
1296 item.iItem = 0;
1297 item.iSubItem = 1;
1298 item.pszText = buffA;
1299 buffA[0] = 'a';
1300 item.cchTextMax = sizeof(buffA);
1301 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1302 expect(1, r);
1303 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1306 /* Query param from subitem: returns main item param */
1307 memset (&item, 0xcc, sizeof (item));
1308 item.mask = LVIF_PARAM;
1309 item.iItem = 0;
1310 item.iSubItem = 1;
1311 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1312 expect(1, r);
1313 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1315 /* Set up param on first subitem: no effect */
1316 memset (&item, 0xcc, sizeof (item));
1317 item.mask = LVIF_PARAM;
1318 item.iItem = 0;
1319 item.iSubItem = 1;
1320 item.lParam = lparamTest+1;
1321 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1322 expect(0, r);
1324 /* Query param from subitem again: should still return main item param */
1325 memset (&item, 0xcc, sizeof (item));
1326 item.mask = LVIF_PARAM;
1327 item.iItem = 0;
1328 item.iSubItem = 1;
1329 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1330 expect(1, r);
1331 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1333 /**** Some tests of state highlighting ****/
1334 memset (&item, 0xcc, sizeof (item));
1335 item.mask = LVIF_STATE;
1336 item.iItem = 0;
1337 item.iSubItem = 0;
1338 item.state = LVIS_SELECTED;
1339 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1340 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1341 expect(1, r);
1342 item.iSubItem = 1;
1343 item.state = LVIS_DROPHILITED;
1344 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1345 expect(1, r);
1347 memset (&item, 0xcc, sizeof (item));
1348 item.mask = LVIF_STATE;
1349 item.iItem = 0;
1350 item.iSubItem = 0;
1351 item.stateMask = -1;
1352 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1353 expect(1, r);
1354 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1355 item.iSubItem = 1;
1356 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1357 expect(1, r);
1358 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1360 /* some notnull but meaningless masks */
1361 memset (&item, 0, sizeof(item));
1362 item.mask = LVIF_NORECOMPUTE;
1363 item.iItem = 0;
1364 item.iSubItem = 0;
1365 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1366 expect(1, r);
1367 memset (&item, 0, sizeof(item));
1368 item.mask = LVIF_DI_SETITEM;
1369 item.iItem = 0;
1370 item.iSubItem = 0;
1371 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1372 expect(1, r);
1374 /* set text to callback value already having it */
1375 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1376 expect(TRUE, r);
1377 memset (&item, 0, sizeof (item));
1378 item.mask = LVIF_TEXT;
1379 item.pszText = LPSTR_TEXTCALLBACKA;
1380 item.iItem = 0;
1381 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1382 expect(0, r);
1383 memset (&item, 0, sizeof (item));
1385 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1387 item.pszText = LPSTR_TEXTCALLBACKA;
1388 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1389 expect(TRUE, r);
1391 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1392 "check callback text comparison rule", FALSE);
1394 DestroyWindow(hwnd);
1397 static void test_columns(void)
1399 HWND hwnd, header;
1400 LVCOLUMNA column;
1401 LVITEMA item;
1402 INT order[2];
1403 CHAR buff[5];
1404 DWORD rc;
1406 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_LIST,
1407 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1408 ok(hwnd != NULL, "failed to create listview window\n");
1410 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1411 ok(header == NULL, "got %p\n", header);
1413 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1414 ok(rc == 0, "got %d\n", rc);
1416 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1417 ok(header == NULL, "got %p\n", header);
1419 DestroyWindow(hwnd);
1421 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1422 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1423 ok(hwnd != NULL, "failed to create listview window\n");
1425 /* Add a column with no mask */
1426 memset(&column, 0xcc, sizeof(column));
1427 column.mask = 0;
1428 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1429 ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1431 /* Check its width */
1432 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1433 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1435 DestroyWindow(hwnd);
1437 /* LVM_GETCOLUMNORDERARRAY */
1438 hwnd = create_listview_control(LVS_REPORT);
1439 subclass_header(hwnd);
1441 memset(&column, 0, sizeof(column));
1442 column.mask = LVCF_WIDTH;
1443 column.cx = 100;
1444 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1445 expect(0, rc);
1447 column.cx = 200;
1448 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1449 expect(1, rc);
1451 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1453 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1454 expect(1, rc);
1455 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1456 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1458 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1459 expect(0, rc);
1461 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1463 /* LVM_SETCOLUMNORDERARRAY */
1464 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1466 order[0] = 0;
1467 order[1] = 1;
1468 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1469 expect(1, rc);
1471 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1472 expect(0, rc);
1474 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1476 /* after column added subitem is considered as present */
1477 insert_item(hwnd, 0);
1479 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1481 item.pszText = buff;
1482 item.cchTextMax = sizeof(buff);
1483 item.iItem = 0;
1484 item.iSubItem = 1;
1485 item.mask = LVIF_TEXT;
1486 memset(&g_itema, 0, sizeof(g_itema));
1487 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1488 expect(1, rc);
1489 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1491 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1492 "get subitem text after column added", FALSE);
1494 DestroyWindow(hwnd);
1497 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1498 static WNDPROC listviewWndProc;
1499 static HIMAGELIST test_create_imagelist;
1501 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1503 LRESULT ret;
1505 if (uMsg == WM_CREATE)
1507 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1508 lpcs->style |= LVS_REPORT;
1510 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1511 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1512 return ret;
1515 static void test_create(void)
1517 HWND hList;
1518 HWND hHeader;
1519 LONG_PTR ret;
1520 LONG r;
1521 LVCOLUMNA col;
1522 RECT rect;
1523 WNDCLASSEXA cls;
1524 DWORD style;
1526 cls.cbSize = sizeof(WNDCLASSEXA);
1527 ok(GetClassInfoExA(GetModuleHandleA(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1528 listviewWndProc = cls.lpfnWndProc;
1529 cls.lpfnWndProc = create_test_wndproc;
1530 cls.lpszClassName = "MyListView32";
1531 ok(RegisterClassExA(&cls), "RegisterClassEx failed\n");
1533 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1534 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1535 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1536 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1538 if (!IsWindow(hHeader))
1540 /* version 4.0 */
1541 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1542 DestroyWindow(hList);
1543 return;
1546 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1547 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1548 DestroyWindow(hList);
1550 /* header isn't created on LVS_ICON and LVS_LIST styles */
1551 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1552 GetModuleHandleA(NULL), 0);
1553 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1554 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1555 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1556 /* insert column */
1557 memset(&col, 0, sizeof(LVCOLUMNA));
1558 col.mask = LVCF_WIDTH;
1559 col.cx = 100;
1560 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1561 expect(0, r);
1562 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1563 ok(IsWindow(hHeader), "Header should be created\n");
1564 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1565 style = GetWindowLongA(hHeader, GWL_STYLE);
1566 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1567 DestroyWindow(hList);
1569 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1570 GetModuleHandleA(NULL), 0);
1571 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1572 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1573 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1574 /* insert column */
1575 memset(&col, 0, sizeof(LVCOLUMNA));
1576 col.mask = LVCF_WIDTH;
1577 col.cx = 100;
1578 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1579 expect(0, r);
1580 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1581 ok(IsWindow(hHeader), "Header should be created\n");
1582 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1583 DestroyWindow(hList);
1585 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1586 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1587 GetModuleHandleA(NULL), 0);
1588 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1589 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1590 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1591 ok(IsWindow(hHeader), "Header should be created\n");
1592 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1593 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1594 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1595 ok(IsWindow(hHeader), "Header should be created\n");
1596 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1597 DestroyWindow(hList);
1599 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1600 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1601 GetModuleHandleA(NULL), 0);
1602 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1603 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1604 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1605 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1606 ok(IsWindow(hHeader), "Header should be created\n");
1607 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1608 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1609 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1610 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1611 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1612 ok(IsWindow(hHeader), "Header should be created\n");
1613 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1614 DestroyWindow(hList);
1616 /* LVS_REPORT without WS_VISIBLE */
1617 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1618 GetModuleHandleA(NULL), 0);
1619 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1620 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1621 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1622 /* insert column */
1623 memset(&col, 0, sizeof(LVCOLUMNA));
1624 col.mask = LVCF_WIDTH;
1625 col.cx = 100;
1626 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1627 expect(0, r);
1628 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1629 ok(IsWindow(hHeader), "Header should be created\n");
1630 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1631 DestroyWindow(hList);
1633 /* LVS_REPORT without WS_VISIBLE, try to show it */
1634 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1635 GetModuleHandleA(NULL), 0);
1636 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1637 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1638 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1639 ShowWindow(hList, SW_SHOW);
1640 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1641 ok(IsWindow(hHeader), "Header should be created\n");
1642 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1643 DestroyWindow(hList);
1645 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1646 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1647 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1648 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1649 ok(IsWindow(hHeader), "Header should be created\n");
1650 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1651 /* HDS_DRAGDROP set by default */
1652 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1653 DestroyWindow(hList);
1655 /* setting LVS_EX_HEADERDRAGDROP creates header */
1656 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1657 GetModuleHandleA(NULL), 0);
1658 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1659 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1660 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1661 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1662 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1663 ok(IsWindow(hHeader) ||
1664 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1665 "Header should be created\n");
1666 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1667 DestroyWindow(hList);
1669 /* setting LVS_EX_GRIDLINES creates header */
1670 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1671 GetModuleHandleA(NULL), 0);
1672 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1673 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1674 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1675 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1676 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1677 ok(IsWindow(hHeader) ||
1678 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1679 "Header should be created\n");
1680 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1681 DestroyWindow(hList);
1683 /* setting LVS_EX_FULLROWSELECT creates header */
1684 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1685 GetModuleHandleA(NULL), 0);
1686 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1687 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1688 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1689 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1690 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1691 ok(IsWindow(hHeader) ||
1692 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1693 "Header should be created\n");
1694 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1695 DestroyWindow(hList);
1697 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1698 hList = create_listview_control(LVS_ICON);
1699 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1700 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1701 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1702 DestroyWindow(hList);
1704 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1705 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1706 GetModuleHandleA(NULL), 0);
1707 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1708 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1710 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1711 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1712 /* right value contains garbage, probably because header columns are not set up */
1713 expect(0, rect.bottom);
1714 expect(1, r);
1716 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1717 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1718 ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1720 DestroyWindow(hList);
1722 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1723 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1724 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1725 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1726 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1727 DestroyWindow(hList);
1730 static void test_redraw(void)
1732 HWND hwnd;
1733 HDC hdc;
1734 BOOL res;
1735 DWORD r;
1737 hwnd = create_listview_control(LVS_REPORT);
1738 subclass_header(hwnd);
1740 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1742 InvalidateRect(hwnd, NULL, TRUE);
1743 UpdateWindow(hwnd);
1744 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1746 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1748 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1749 /* 1. Without backbuffer */
1750 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1751 expect(TRUE, res);
1753 hdc = GetWindowDC(hwndparent);
1755 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1756 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1757 ok(r == 1, "Expected not zero result\n");
1758 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1759 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1761 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1762 expect(TRUE, res);
1764 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1765 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1766 expect(1, r);
1767 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1768 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1770 /* 2. With backbuffer */
1771 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1772 LVS_EX_DOUBLEBUFFER);
1773 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1774 expect(TRUE, res);
1776 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1777 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1778 expect(1, r);
1779 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1780 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1782 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1783 expect(TRUE, res);
1785 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1786 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1787 todo_wine expect(1, r);
1788 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1789 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1791 ReleaseDC(hwndparent, hdc);
1793 DestroyWindow(hwnd);
1796 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1798 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1800 if(message == WM_NOTIFY) {
1801 NMHDR *nmhdr = (NMHDR*)lParam;
1802 if(nmhdr->code == NM_CUSTOMDRAW) {
1803 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1804 struct message msg;
1806 msg.message = message;
1807 msg.flags = sent|wparam|lparam|custdraw;
1808 msg.wParam = wParam;
1809 msg.lParam = lParam;
1810 msg.id = nmhdr->code;
1811 msg.stage = nmlvcd->nmcd.dwDrawStage;
1812 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1814 switch(nmlvcd->nmcd.dwDrawStage) {
1815 case CDDS_PREPAINT:
1816 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1817 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1818 case CDDS_ITEMPREPAINT:
1819 nmlvcd->clrTextBk = CLR_DEFAULT;
1820 nmlvcd->clrText = RGB(0, 255, 0);
1821 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1822 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1823 clr = GetBkColor(nmlvcd->nmcd.hdc);
1824 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1825 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1826 if (nmlvcd->iSubItem)
1827 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1828 else
1829 ok(clr == c0ffee, "clr=%.8x\n", clr);
1830 return CDRF_NOTIFYPOSTPAINT;
1831 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1832 clr = GetBkColor(nmlvcd->nmcd.hdc);
1833 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1834 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1835 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1836 return CDRF_DODEFAULT;
1838 return CDRF_DODEFAULT;
1842 return DefWindowProcA(hwnd, message, wParam, lParam);
1845 static void test_customdraw(void)
1847 HWND hwnd;
1848 WNDPROC oldwndproc;
1850 hwnd = create_listview_control(LVS_REPORT);
1852 insert_column(hwnd, 0);
1853 insert_column(hwnd, 1);
1854 insert_item(hwnd, 0);
1856 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
1857 (LONG_PTR)cd_wndproc);
1859 InvalidateRect(hwnd, NULL, TRUE);
1860 UpdateWindow(hwnd);
1862 /* message tests */
1863 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1864 InvalidateRect(hwnd, NULL, TRUE);
1865 UpdateWindow(hwnd);
1866 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1868 DestroyWindow(hwnd);
1870 hwnd = create_listview_control(LVS_LIST);
1872 insert_column(hwnd, 0);
1873 insert_column(hwnd, 1);
1874 insert_item(hwnd, 0);
1876 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1877 InvalidateRect(hwnd, NULL, TRUE);
1878 UpdateWindow(hwnd);
1879 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1881 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1882 DestroyWindow(hwnd);
1885 static void test_icon_spacing(void)
1887 /* LVM_SETICONSPACING */
1888 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1890 HWND hwnd;
1891 WORD w, h;
1892 INT r;
1894 hwnd = create_listview_control(LVS_ICON);
1895 ok(hwnd != NULL, "failed to create a listview window\n");
1897 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1898 expect(NFR_ANSI, r);
1900 /* reset the icon spacing to defaults */
1901 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1903 /* now we can request what the defaults are */
1904 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1905 w = LOWORD(r);
1906 h = HIWORD(r);
1908 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1910 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1911 ok(r == MAKELONG(w, h) ||
1912 broken(r == MAKELONG(w, w)), /* win98 */
1913 "Expected %d, got %d\n", MAKELONG(w, h), r);
1915 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1916 if (r == 0)
1918 /* version 4.0 */
1919 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1920 DestroyWindow(hwnd);
1921 return;
1923 expect(MAKELONG(20,30), r);
1925 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1926 expect(MAKELONG(25,35), r);
1928 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1930 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1931 DestroyWindow(hwnd);
1934 static void test_color(void)
1936 RECT rect;
1937 HWND hwnd;
1938 DWORD r;
1939 int i;
1941 COLORREF color;
1942 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1944 hwnd = create_listview_control(LVS_REPORT);
1945 ok(hwnd != NULL, "failed to create a listview window\n");
1947 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1949 for (i = 0; i < 4; i++)
1951 color = colors[i];
1953 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
1954 expect(TRUE, r);
1955 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
1956 expect(color, r);
1958 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
1959 expect (TRUE, r);
1960 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1961 expect(color, r);
1963 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1964 expect(TRUE, r);
1965 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1966 expect(color, r);
1969 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1970 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1972 /* invalidation test done separately to avoid a message chain mess */
1973 r = ValidateRect(hwnd, NULL);
1974 expect(TRUE, r);
1975 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
1976 expect(TRUE, r);
1978 rect.right = rect.bottom = 1;
1979 r = GetUpdateRect(hwnd, &rect, TRUE);
1980 todo_wine expect(FALSE, r);
1981 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1983 r = ValidateRect(hwnd, NULL);
1984 expect(TRUE, r);
1985 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
1986 expect(TRUE, r);
1988 rect.right = rect.bottom = 1;
1989 r = GetUpdateRect(hwnd, &rect, TRUE);
1990 todo_wine expect(FALSE, r);
1991 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1993 r = ValidateRect(hwnd, NULL);
1994 expect(TRUE, r);
1995 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
1996 expect(TRUE, r);
1998 rect.right = rect.bottom = 1;
1999 r = GetUpdateRect(hwnd, &rect, TRUE);
2000 todo_wine expect(FALSE, r);
2001 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2003 DestroyWindow(hwnd);
2006 static void test_item_count(void)
2008 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2010 HWND hwnd;
2011 DWORD r;
2012 HDC hdc;
2013 HFONT hOldFont;
2014 TEXTMETRICA tm;
2015 RECT rect;
2016 INT height;
2018 LVITEMA item0;
2019 LVITEMA item1;
2020 LVITEMA item2;
2021 static CHAR item0text[] = "item0";
2022 static CHAR item1text[] = "item1";
2023 static CHAR item2text[] = "item2";
2025 hwnd = create_listview_control(LVS_REPORT);
2026 ok(hwnd != NULL, "failed to create a listview window\n");
2028 /* resize in dpiaware manner to fit all 3 items added */
2029 hdc = GetDC(0);
2030 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2031 GetTextMetricsA(hdc, &tm);
2032 /* 2 extra pixels for bounds and header border */
2033 height = tm.tmHeight + 2;
2034 SelectObject(hdc, hOldFont);
2035 ReleaseDC(0, hdc);
2037 GetWindowRect(hwnd, &rect);
2038 /* 3 items + 1 header + 1 to be sure */
2039 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2041 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2043 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2044 expect(0, r);
2046 /* [item0] */
2047 item0.mask = LVIF_TEXT;
2048 item0.iItem = 0;
2049 item0.iSubItem = 0;
2050 item0.pszText = item0text;
2051 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2052 expect(0, r);
2054 /* [item0, item1] */
2055 item1.mask = LVIF_TEXT;
2056 item1.iItem = 1;
2057 item1.iSubItem = 0;
2058 item1.pszText = item1text;
2059 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2060 expect(1, r);
2062 /* [item0, item1, item2] */
2063 item2.mask = LVIF_TEXT;
2064 item2.iItem = 2;
2065 item2.iSubItem = 0;
2066 item2.pszText = item2text;
2067 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2068 expect(2, r);
2070 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2071 expect(3, r);
2073 /* [item0, item1] */
2074 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2075 expect(TRUE, r);
2077 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2078 expect(2, r);
2080 /* [] */
2081 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2082 expect(TRUE, r);
2084 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2085 expect(0, r);
2087 /* [item0] */
2088 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2089 expect(0, r);
2091 /* [item0, item1] */
2092 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2093 expect(1, r);
2095 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2096 expect(2, r);
2098 /* [item0, item1, item2] */
2099 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2100 expect(2, r);
2102 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2103 expect(3, r);
2105 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2107 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2108 DestroyWindow(hwnd);
2111 static void test_item_position(void)
2113 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2115 HWND hwnd;
2116 DWORD r;
2117 POINT position;
2119 LVITEMA item0;
2120 LVITEMA item1;
2121 LVITEMA item2;
2122 static CHAR item0text[] = "item0";
2123 static CHAR item1text[] = "item1";
2124 static CHAR item2text[] = "item2";
2126 hwnd = create_listview_control(LVS_ICON);
2127 ok(hwnd != NULL, "failed to create a listview window\n");
2129 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2131 /* [item0] */
2132 item0.mask = LVIF_TEXT;
2133 item0.iItem = 0;
2134 item0.iSubItem = 0;
2135 item0.pszText = item0text;
2136 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2137 expect(0, r);
2139 /* [item0, item1] */
2140 item1.mask = LVIF_TEXT;
2141 item1.iItem = 1;
2142 item1.iSubItem = 0;
2143 item1.pszText = item1text;
2144 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2145 expect(1, r);
2147 /* [item0, item1, item2] */
2148 item2.mask = LVIF_TEXT;
2149 item2.iItem = 2;
2150 item2.iSubItem = 0;
2151 item2.pszText = item2text;
2152 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2153 expect(2, r);
2155 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2156 expect(TRUE, r);
2157 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2158 expect(TRUE, r);
2159 expect2(10, 5, position.x, position.y);
2161 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2162 expect(TRUE, r);
2163 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2164 expect(TRUE, r);
2165 expect2(0, 0, position.x, position.y);
2167 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2168 expect(TRUE, r);
2169 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2170 expect(TRUE, r);
2171 expect2(20, 20, position.x, position.y);
2173 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2175 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2176 DestroyWindow(hwnd);
2179 static void test_getorigin(void)
2181 /* LVM_GETORIGIN */
2183 HWND hwnd;
2184 DWORD r;
2185 POINT position;
2187 position.x = position.y = 0;
2189 hwnd = create_listview_control(LVS_ICON);
2190 ok(hwnd != NULL, "failed to create a listview window\n");
2191 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2193 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2194 expect(TRUE, r);
2195 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2196 DestroyWindow(hwnd);
2198 hwnd = create_listview_control(LVS_SMALLICON);
2199 ok(hwnd != NULL, "failed to create a listview window\n");
2200 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2202 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2203 expect(TRUE, r);
2204 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2205 DestroyWindow(hwnd);
2207 hwnd = create_listview_control(LVS_LIST);
2208 ok(hwnd != NULL, "failed to create a listview window\n");
2209 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2211 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2212 expect(FALSE, r);
2213 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2214 DestroyWindow(hwnd);
2216 hwnd = create_listview_control(LVS_REPORT);
2217 ok(hwnd != NULL, "failed to create a listview window\n");
2218 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2220 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2221 expect(FALSE, r);
2222 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2223 DestroyWindow(hwnd);
2226 static void test_multiselect(void)
2228 typedef struct t_select_task
2230 const char *descr;
2231 int initPos;
2232 int loopVK;
2233 int count;
2234 int result;
2235 } select_task;
2237 HWND hwnd;
2238 INT r;
2239 int i,j,item_count,selected_count;
2240 static const int items=5;
2241 BYTE kstate[256];
2242 select_task task;
2243 LONG_PTR style;
2244 LVITEMA item;
2246 static struct t_select_task task_list[] = {
2247 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2248 { "using VK_UP", -1, VK_UP, -1, -1 },
2249 { "using VK_END", 0, VK_END, 1, -1 },
2250 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2253 hwnd = create_listview_control(LVS_REPORT);
2255 for (i = 0; i < items; i++)
2256 insert_item(hwnd, 0);
2258 item_count = (int)SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2259 expect(items, item_count);
2261 for (i = 0; i < 4; i++) {
2262 LVITEMA item;
2264 task = task_list[i];
2266 /* deselect all items */
2267 item.state = 0;
2268 item.stateMask = LVIS_SELECTED;
2269 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2270 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2272 /* set initial position */
2273 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2275 item.state = LVIS_SELECTED;
2276 item.stateMask = LVIS_SELECTED;
2277 SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2279 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2280 ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2282 /* Set SHIFT key pressed */
2283 GetKeyboardState(kstate);
2284 kstate[VK_SHIFT]=0x80;
2285 SetKeyboardState(kstate);
2287 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2288 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2289 expect(0,r);
2290 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2291 expect(0,r);
2294 selected_count = (int)SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2296 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);
2298 /* Set SHIFT key released */
2299 GetKeyboardState(kstate);
2300 kstate[VK_SHIFT]=0x00;
2301 SetKeyboardState(kstate);
2303 DestroyWindow(hwnd);
2305 /* make multiple selection, then switch to LVS_SINGLESEL */
2306 hwnd = create_listview_control(LVS_REPORT);
2307 for (i=0;i<items;i++) {
2308 insert_item(hwnd, 0);
2310 item_count = (int)SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2311 expect(items,item_count);
2313 /* try with NULL pointer */
2314 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2315 expect(FALSE, r);
2317 /* select all, check notifications */
2318 item.state = 0;
2319 item.stateMask = LVIS_SELECTED;
2320 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2322 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2324 item.stateMask = LVIS_SELECTED;
2325 item.state = LVIS_SELECTED;
2326 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2327 expect(TRUE, r);
2329 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2330 "select all notification", FALSE);
2332 /* select all again (all selected already) */
2333 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2335 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2337 item.stateMask = LVIS_SELECTED;
2338 item.state = LVIS_SELECTED;
2339 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2340 expect(TRUE, r);
2342 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2343 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2344 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2346 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2347 "select all notification 2", FALSE);
2349 /* deselect all items */
2350 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2352 item.state = 0;
2353 item.stateMask = LVIS_SELECTED;
2354 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2356 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2357 "deselect all notification", FALSE);
2359 /* deselect all items again */
2360 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2361 item.state = 0;
2362 item.stateMask = LVIS_SELECTED;
2363 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2364 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2366 /* any non-zero state value does the same */
2367 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2369 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2371 item.stateMask = LVIS_SELECTED;
2372 item.state = LVIS_CUT;
2373 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2374 expect(TRUE, r);
2376 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2377 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2378 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2380 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2381 "set state all notification 3", FALSE);
2383 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2384 for (i = 0; i < 3; i++) {
2385 item.state = LVIS_SELECTED;
2386 item.stateMask = LVIS_SELECTED;
2387 SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2390 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2391 expect(3, r);
2392 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2393 expect(-1, r);
2395 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2396 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2397 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2398 /* check that style is accepted */
2399 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2400 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2402 for (i=0;i<3;i++) {
2403 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2404 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2406 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2407 expect(3, r);
2408 SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2409 expect(3, r);
2411 /* select one more */
2412 item.state = LVIS_SELECTED;
2413 item.stateMask = LVIS_SELECTED;
2414 SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2416 for (i=0;i<3;i++) {
2417 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2418 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2421 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2422 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2424 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2425 expect(1, r);
2426 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2427 expect(-1, r);
2429 /* try to select all on LVS_SINGLESEL */
2430 memset(&item, 0, sizeof(item));
2431 item.stateMask = LVIS_SELECTED;
2432 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2433 expect(TRUE, r);
2434 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2436 item.stateMask = LVIS_SELECTED;
2437 item.state = LVIS_SELECTED;
2438 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2439 expect(FALSE, r);
2441 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2442 expect(0, r);
2443 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2444 expect(-1, r);
2446 /* try to deselect all on LVS_SINGLESEL */
2447 item.stateMask = LVIS_SELECTED;
2448 item.state = LVIS_SELECTED;
2449 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2450 expect(TRUE, r);
2452 item.stateMask = LVIS_SELECTED;
2453 item.state = 0;
2454 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2455 expect(TRUE, r);
2456 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2457 expect(0, r);
2459 /* 1. selection mark is update when new focused item is set */
2460 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2461 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2463 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2464 expect(-1, r);
2466 item.stateMask = LVIS_FOCUSED;
2467 item.state = LVIS_FOCUSED;
2468 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2469 expect(TRUE, r);
2471 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2472 expect(0, r);
2474 /* it's not updated if already set */
2475 item.stateMask = LVIS_FOCUSED;
2476 item.state = LVIS_FOCUSED;
2477 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2478 expect(TRUE, r);
2480 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2481 expect(0, r);
2483 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2484 expect(0, r);
2486 item.stateMask = LVIS_FOCUSED;
2487 item.state = LVIS_FOCUSED;
2488 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2489 expect(TRUE, r);
2491 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2492 expect(-1, r);
2494 /* need to reset focused item first */
2495 item.stateMask = LVIS_FOCUSED;
2496 item.state = 0;
2497 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2498 expect(TRUE, r);
2500 item.stateMask = LVIS_FOCUSED;
2501 item.state = LVIS_FOCUSED;
2502 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2503 expect(TRUE, r);
2505 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2506 expect(2, r);
2508 item.stateMask = LVIS_FOCUSED;
2509 item.state = 0;
2510 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2511 expect(TRUE, r);
2513 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2514 expect(2, r);
2516 /* 2. same tests, with LVM_SETITEM */
2517 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2518 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2520 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2521 expect(2, r);
2523 item.stateMask = LVIS_FOCUSED;
2524 item.state = LVIS_FOCUSED;
2525 item.mask = LVIF_STATE;
2526 item.iItem = item.iSubItem = 0;
2527 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2528 expect(TRUE, r);
2530 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2531 expect(0, r);
2533 /* it's not updated if already set */
2534 item.stateMask = LVIS_FOCUSED;
2535 item.state = LVIS_FOCUSED;
2536 item.mask = LVIF_STATE;
2537 item.iItem = 1;
2538 item.iSubItem = 0;
2539 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2540 expect(TRUE, r);
2542 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2543 expect(0, r);
2545 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2546 expect(0, r);
2548 item.stateMask = LVIS_FOCUSED;
2549 item.state = LVIS_FOCUSED;
2550 item.mask = LVIF_STATE;
2551 item.iItem = 1;
2552 item.iSubItem = 0;
2553 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2554 expect(TRUE, r);
2556 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2557 expect(-1, r);
2559 /* need to reset focused item first */
2560 item.stateMask = LVIS_FOCUSED;
2561 item.state = 0;
2562 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2563 expect(TRUE, r);
2565 item.stateMask = LVIS_FOCUSED;
2566 item.state = LVIS_FOCUSED;
2567 item.mask = LVIF_STATE;
2568 item.iItem = 2;
2569 item.iSubItem = 0;
2570 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2571 expect(TRUE, r);
2573 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2574 expect(2, r);
2576 item.stateMask = LVIS_FOCUSED;
2577 item.state = 0;
2578 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2579 expect(TRUE, r);
2581 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2582 expect(2, r);
2584 DestroyWindow(hwnd);
2587 static void test_subitem_rect(void)
2589 HWND hwnd;
2590 DWORD r;
2591 LVCOLUMNA col;
2592 RECT rect, rect2;
2593 INT arr[3];
2595 /* test LVM_GETSUBITEMRECT for header */
2596 hwnd = create_listview_control(LVS_REPORT);
2597 ok(hwnd != NULL, "failed to create a listview window\n");
2598 /* add some columns */
2599 memset(&col, 0, sizeof(LVCOLUMNA));
2600 col.mask = LVCF_WIDTH;
2601 col.cx = 100;
2602 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2603 expect(0, r);
2604 col.cx = 150;
2605 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2606 expect(1, r);
2607 col.cx = 200;
2608 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2609 expect(2, r);
2610 /* item = -1 means header, subitem index is 1 based */
2611 SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2612 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2613 expect(0, r);
2615 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2616 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2617 expect(1, r);
2619 expect(100, rect.left);
2620 expect(250, rect.right);
2621 expect(3, rect.top);
2623 SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2624 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2625 expect(1, r);
2627 expect(250, rect.left);
2628 expect(450, rect.right);
2629 expect(3, rect.top);
2631 /* item LVS_REPORT padding isn't applied to subitems */
2632 insert_item(hwnd, 0);
2634 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2635 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2636 expect(1, r);
2637 expect(100, rect.left);
2638 expect(250, rect.right);
2640 SetRect(&rect, LVIR_ICON, 1, 0, 0);
2641 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2642 expect(1, r);
2643 /* no icon attached - zero width rectangle, with no left padding */
2644 expect(100, rect.left);
2645 expect(100, rect.right);
2647 SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2648 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2649 expect(1, r);
2650 /* same as full LVIR_BOUNDS */
2651 expect(100, rect.left);
2652 expect(250, rect.right);
2654 SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2656 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2657 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2658 expect(1, r);
2659 expect(90, rect.left);
2660 expect(240, rect.right);
2662 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2664 /* test header interaction */
2665 subclass_header(hwnd);
2666 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2668 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2669 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2670 expect(1, r);
2672 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2673 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2674 expect(1, r);
2676 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2677 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2678 expect(1, r);
2680 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2681 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2682 expect(1, r);
2684 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2686 DestroyWindow(hwnd);
2688 /* test subitem rects after re-arranging columns */
2689 hwnd = create_listview_control(LVS_REPORT);
2690 ok(hwnd != NULL, "failed to create a listview window\n");
2691 memset(&col, 0, sizeof(LVCOLUMNA));
2692 col.mask = LVCF_WIDTH;
2694 col.cx = 100;
2695 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2696 expect(0, r);
2698 col.cx = 200;
2699 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2700 expect(1, r);
2702 col.cx = 300;
2703 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2704 expect(2, r);
2706 insert_item(hwnd, 0);
2707 insert_item(hwnd, 1);
2709 /* wrong item is refused for main item */
2710 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2711 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2712 expect(FALSE, r);
2714 /* for subitems rectangle is calculated even if there's no item added */
2715 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2716 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2717 expect(TRUE, r);
2719 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2720 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2721 expect(TRUE, r);
2722 expect(rect.right, rect2.right);
2723 expect(rect.left, rect2.left);
2724 expect(rect.bottom, rect2.top);
2725 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2727 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2728 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2729 expect(TRUE, r);
2731 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2732 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2733 expect(TRUE, r);
2734 expect(0, rect.left);
2735 expect(600, rect.right);
2737 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2738 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2739 expect(TRUE, r);
2740 expect(0, rect.left);
2741 expect(200, rect.right);
2743 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2744 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2745 expect(TRUE, r);
2746 expect(0, rect2.left);
2747 expect(200, rect2.right);
2748 /* items are of the same height */
2749 ok(rect2.top > 0, "expected positive item height\n");
2750 expect(rect.bottom, rect2.top);
2751 expect(rect.bottom * 2 - rect.top, rect2.bottom);
2753 SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
2754 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2755 expect(TRUE, r);
2756 expect(300, rect.left);
2757 expect(600, rect.right);
2759 DestroyWindow(hwnd);
2761 /* try it for non LVS_REPORT style */
2762 hwnd = CreateWindowA("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2763 GetModuleHandleA(NULL), 0);
2764 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
2765 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2766 expect(0, r);
2767 /* rect is unchanged */
2768 expect(0, rect.left);
2769 expect(-10, rect.right);
2770 expect(1, rect.top);
2771 expect(-10, rect.bottom);
2772 DestroyWindow(hwnd);
2775 /* comparison callback for test_sorting */
2776 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2778 if (first == second) return 0;
2779 return (first > second ? 1 : -1);
2782 static void test_sorting(void)
2784 HWND hwnd;
2785 LVITEMA item = {0};
2786 INT r;
2787 LONG_PTR style;
2788 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2789 CHAR buff[10];
2791 hwnd = create_listview_control(LVS_REPORT);
2792 ok(hwnd != NULL, "failed to create a listview window\n");
2794 /* insert some items */
2795 item.mask = LVIF_PARAM | LVIF_STATE;
2796 item.state = LVIS_SELECTED;
2797 item.iItem = 0;
2798 item.iSubItem = 0;
2799 item.lParam = 3;
2800 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2801 expect(0, r);
2803 item.mask = LVIF_PARAM;
2804 item.iItem = 1;
2805 item.iSubItem = 0;
2806 item.lParam = 2;
2807 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2808 expect(1, r);
2810 item.mask = LVIF_STATE | LVIF_PARAM;
2811 item.state = LVIS_SELECTED;
2812 item.iItem = 2;
2813 item.iSubItem = 0;
2814 item.lParam = 4;
2815 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2816 expect(2, r);
2818 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2819 expect(-1, r);
2821 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2822 expect(2, r);
2824 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2825 expect(TRUE, r);
2827 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2828 expect(2, r);
2829 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2830 expect(-1, r);
2831 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2832 expect(0, r);
2833 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2834 expect(LVIS_SELECTED, r);
2835 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2836 expect(LVIS_SELECTED, r);
2838 DestroyWindow(hwnd);
2840 /* switch to LVS_SORTASCENDING when some items added */
2841 hwnd = create_listview_control(LVS_REPORT);
2842 ok(hwnd != NULL, "failed to create a listview window\n");
2844 item.mask = LVIF_TEXT;
2845 item.iItem = 0;
2846 item.iSubItem = 0;
2847 item.pszText = names[1];
2848 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2849 expect(0, r);
2851 item.mask = LVIF_TEXT;
2852 item.iItem = 1;
2853 item.iSubItem = 0;
2854 item.pszText = names[2];
2855 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2856 expect(1, r);
2858 item.mask = LVIF_TEXT;
2859 item.iItem = 2;
2860 item.iSubItem = 0;
2861 item.pszText = names[0];
2862 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2863 expect(2, r);
2865 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2866 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2867 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2868 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2870 /* no sorting performed when switched to LVS_SORTASCENDING */
2871 item.mask = LVIF_TEXT;
2872 item.iItem = 0;
2873 item.pszText = buff;
2874 item.cchTextMax = sizeof(buff);
2875 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2876 expect(TRUE, r);
2877 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2879 item.iItem = 1;
2880 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2881 expect(TRUE, r);
2882 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2884 item.iItem = 2;
2885 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2886 expect(TRUE, r);
2887 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2889 /* adding new item doesn't resort list */
2890 item.mask = LVIF_TEXT;
2891 item.iItem = 3;
2892 item.iSubItem = 0;
2893 item.pszText = names[3];
2894 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2895 expect(3, r);
2897 item.mask = LVIF_TEXT;
2898 item.iItem = 0;
2899 item.pszText = buff;
2900 item.cchTextMax = sizeof(buff);
2901 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2902 expect(TRUE, r);
2903 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2905 item.iItem = 1;
2906 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2907 expect(TRUE, r);
2908 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2910 item.iItem = 2;
2911 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2912 expect(TRUE, r);
2913 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2915 item.iItem = 3;
2916 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2917 expect(TRUE, r);
2918 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2920 /* corner case - item should be placed at first position */
2921 item.mask = LVIF_TEXT;
2922 item.iItem = 4;
2923 item.iSubItem = 0;
2924 item.pszText = names[4];
2925 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2926 expect(0, r);
2928 item.iItem = 0;
2929 item.pszText = buff;
2930 item.cchTextMax = sizeof(buff);
2931 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2932 expect(TRUE, r);
2933 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2935 item.iItem = 1;
2936 item.pszText = buff;
2937 item.cchTextMax = sizeof(buff);
2938 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2939 expect(TRUE, r);
2940 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2942 item.iItem = 2;
2943 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2944 expect(TRUE, r);
2945 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2947 item.iItem = 3;
2948 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2949 expect(TRUE, r);
2950 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2952 item.iItem = 4;
2953 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2954 expect(TRUE, r);
2955 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2957 DestroyWindow(hwnd);
2960 static void test_ownerdata(void)
2962 static char test_str[] = "test";
2964 HWND hwnd;
2965 LONG_PTR style, ret;
2966 DWORD res;
2967 LVITEMA item;
2969 /* it isn't possible to set LVS_OWNERDATA after creation */
2970 if (g_is_below_5)
2972 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2974 else
2976 hwnd = create_listview_control(LVS_REPORT);
2977 ok(hwnd != NULL, "failed to create a listview window\n");
2978 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2979 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
2981 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2983 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2984 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2985 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2986 "try to switch to LVS_OWNERDATA seq", FALSE);
2988 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2989 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
2990 DestroyWindow(hwnd);
2993 /* try to set LVS_OWNERDATA after creation just having it */
2994 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2995 ok(hwnd != NULL, "failed to create a listview window\n");
2996 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2997 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2999 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3001 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3002 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3003 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3004 "try to switch to LVS_OWNERDATA seq", FALSE);
3005 DestroyWindow(hwnd);
3007 /* try to remove LVS_OWNERDATA after creation just having it */
3008 if (g_is_below_5)
3010 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3012 else
3014 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3015 ok(hwnd != NULL, "failed to create a listview window\n");
3016 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3017 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3019 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3021 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3022 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3023 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3024 "try to switch to LVS_OWNERDATA seq", FALSE);
3025 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3026 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3027 DestroyWindow(hwnd);
3030 /* try select an item */
3031 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3032 ok(hwnd != NULL, "failed to create a listview window\n");
3033 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3034 expect(1, res);
3035 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3036 expect(0, res);
3037 memset(&item, 0, sizeof(item));
3038 item.stateMask = LVIS_SELECTED;
3039 item.state = LVIS_SELECTED;
3040 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3041 expect(TRUE, res);
3042 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3043 expect(1, res);
3044 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3045 expect(1, res);
3046 DestroyWindow(hwnd);
3048 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3049 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3050 ok(hwnd != NULL, "failed to create a listview window\n");
3051 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3052 expect(1, res);
3053 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3054 expect(1, res);
3055 memset(&item, 0, sizeof(item));
3056 item.mask = LVIF_STATE;
3057 item.iItem = 0;
3058 item.stateMask = LVIS_SELECTED;
3059 item.state = LVIS_SELECTED;
3060 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3061 expect(FALSE, res);
3062 memset(&item, 0, sizeof(item));
3063 item.pszText = test_str;
3064 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3065 expect(FALSE, res);
3066 DestroyWindow(hwnd);
3068 /* check notifications after focused/selected changed */
3069 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3070 ok(hwnd != NULL, "failed to create a listview window\n");
3071 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3072 expect(1, res);
3074 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3076 memset(&item, 0, sizeof(item));
3077 item.stateMask = LVIS_SELECTED;
3078 item.state = LVIS_SELECTED;
3079 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3080 expect(TRUE, res);
3082 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3083 "ownerdata select notification", TRUE);
3085 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3087 memset(&item, 0, sizeof(item));
3088 item.stateMask = LVIS_FOCUSED;
3089 item.state = LVIS_FOCUSED;
3090 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3091 expect(TRUE, res);
3093 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3094 "ownerdata focus notification", TRUE);
3096 /* select all, check notifications */
3097 item.stateMask = LVIS_SELECTED;
3098 item.state = 0;
3099 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3100 expect(TRUE, res);
3102 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3104 item.stateMask = LVIS_SELECTED;
3105 item.state = LVIS_SELECTED;
3107 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3108 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3109 expect(TRUE, res);
3110 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3111 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3112 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3113 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3114 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3115 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3116 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3118 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3119 "ownerdata select all notification", FALSE);
3121 /* select all again, note that all items are selected already */
3122 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3123 item.stateMask = LVIS_SELECTED;
3124 item.state = LVIS_SELECTED;
3126 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3127 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3128 expect(TRUE, res);
3129 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3130 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3131 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3132 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3133 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3134 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3135 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3137 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3138 "ownerdata select all notification", FALSE);
3140 /* deselect all */
3141 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3142 item.stateMask = LVIS_SELECTED;
3143 item.state = 0;
3145 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3146 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3147 expect(TRUE, res);
3148 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3149 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3150 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3151 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3152 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3153 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3154 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3156 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3157 "ownerdata deselect all notification", TRUE);
3159 /* nothing selected, deselect all again */
3160 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3161 item.stateMask = LVIS_SELECTED;
3162 item.state = 0;
3164 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3165 expect(TRUE, res);
3167 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3169 /* select one, then deselect all */
3170 item.stateMask = LVIS_SELECTED;
3171 item.state = LVIS_SELECTED;
3172 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3173 expect(TRUE, res);
3174 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3175 item.stateMask = LVIS_SELECTED;
3176 item.state = 0;
3178 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3179 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3180 expect(TRUE, res);
3181 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3182 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3183 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3184 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3185 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3186 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3187 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3189 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3190 "ownerdata select all notification", TRUE);
3192 /* remove focused, try to focus all */
3193 item.stateMask = LVIS_FOCUSED;
3194 item.state = LVIS_FOCUSED;
3195 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3196 expect(TRUE, res);
3197 item.stateMask = LVIS_FOCUSED;
3198 item.state = 0;
3199 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3200 expect(TRUE, res);
3201 item.stateMask = LVIS_FOCUSED;
3202 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3203 expect(0, res);
3205 /* setting all to focused returns failure value */
3206 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3207 item.stateMask = LVIS_FOCUSED;
3208 item.state = LVIS_FOCUSED;
3210 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3211 expect(FALSE, res);
3213 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3214 "ownerdata focus all notification", FALSE);
3216 /* focus single item, remove all */
3217 item.stateMask = LVIS_FOCUSED;
3218 item.state = LVIS_FOCUSED;
3219 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3220 expect(TRUE, res);
3221 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3222 item.stateMask = LVIS_FOCUSED;
3223 item.state = 0;
3225 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3226 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3227 expect(TRUE, res);
3228 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3229 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3230 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3231 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3232 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3233 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3234 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3236 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3237 "ownerdata remove focus all notification", TRUE);
3239 /* set all cut */
3240 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3241 item.stateMask = LVIS_CUT;
3242 item.state = LVIS_CUT;
3244 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3245 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3246 expect(TRUE, res);
3247 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3248 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3249 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3250 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3251 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3252 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3253 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3255 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3256 "ownerdata cut all notification", FALSE);
3258 /* all marked cut, try again */
3259 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3260 item.stateMask = LVIS_CUT;
3261 item.state = LVIS_CUT;
3263 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3264 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3265 expect(TRUE, res);
3266 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3267 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3268 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3269 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3270 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3271 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3272 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3274 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3275 "ownerdata cut all notification #2", FALSE);
3277 DestroyWindow(hwnd);
3279 /* check notifications on LVM_GETITEM */
3280 /* zero callback mask */
3281 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3282 ok(hwnd != NULL, "failed to create a listview window\n");
3283 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3284 expect(1, res);
3286 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3288 memset(&item, 0, sizeof(item));
3289 item.stateMask = LVIS_SELECTED;
3290 item.mask = LVIF_STATE;
3291 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3292 expect(TRUE, res);
3294 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3295 "ownerdata getitem selected state 1", FALSE);
3297 /* non zero callback mask but not we asking for */
3298 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3299 expect(TRUE, res);
3301 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3303 memset(&item, 0, sizeof(item));
3304 item.stateMask = LVIS_SELECTED;
3305 item.mask = LVIF_STATE;
3306 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3307 expect(TRUE, res);
3309 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3310 "ownerdata getitem selected state 2", FALSE);
3312 /* LVIS_OVERLAYMASK callback mask, asking for index */
3313 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3315 memset(&item, 0, sizeof(item));
3316 item.stateMask = LVIS_OVERLAYMASK;
3317 item.mask = LVIF_STATE;
3318 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3319 expect(TRUE, res);
3321 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3322 "ownerdata getitem selected state 2", FALSE);
3324 DestroyWindow(hwnd);
3326 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3327 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3328 ok(hwnd != NULL, "failed to create a listview window\n");
3329 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3330 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3331 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3332 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3333 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3334 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3335 DestroyWindow(hwnd);
3336 /* apparently it's allowed to switch these style on after creation */
3337 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3338 ok(hwnd != NULL, "failed to create a listview window\n");
3339 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3340 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3341 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3342 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3343 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3344 DestroyWindow(hwnd);
3346 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3347 ok(hwnd != NULL, "failed to create a listview window\n");
3348 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3349 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3350 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3351 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3352 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3353 DestroyWindow(hwnd);
3355 /* The focused item is updated after the invalidation */
3356 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3357 ok(hwnd != NULL, "failed to create a listview window\n");
3358 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3359 expect(TRUE, res);
3361 memset(&item, 0, sizeof(item));
3362 item.stateMask = LVIS_FOCUSED;
3363 item.state = LVIS_FOCUSED;
3364 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3365 expect(TRUE, res);
3367 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3368 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3369 expect(TRUE, res);
3370 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3371 "ownerdata setitemcount", FALSE);
3373 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3374 expect(-1, res);
3375 DestroyWindow(hwnd);
3378 static void test_norecompute(void)
3380 static CHAR testA[] = "test";
3381 CHAR buff[10];
3382 LVITEMA item;
3383 HWND hwnd;
3384 DWORD res;
3386 /* self containing control */
3387 hwnd = create_listview_control(LVS_REPORT);
3388 ok(hwnd != NULL, "failed to create a listview window\n");
3389 memset(&item, 0, sizeof(item));
3390 item.mask = LVIF_TEXT | LVIF_STATE;
3391 item.iItem = 0;
3392 item.stateMask = LVIS_SELECTED;
3393 item.state = LVIS_SELECTED;
3394 item.pszText = testA;
3395 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3396 expect(0, res);
3397 /* retrieve with LVIF_NORECOMPUTE */
3398 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3399 item.iItem = 0;
3400 item.pszText = buff;
3401 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3402 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3403 expect(TRUE, res);
3404 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3406 item.mask = LVIF_TEXT;
3407 item.iItem = 1;
3408 item.pszText = LPSTR_TEXTCALLBACKA;
3409 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3410 expect(1, res);
3412 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3413 item.iItem = 1;
3414 item.pszText = buff;
3415 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3417 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3418 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3419 expect(TRUE, res);
3420 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3421 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3422 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3424 DestroyWindow(hwnd);
3426 /* LVS_OWNERDATA */
3427 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3428 ok(hwnd != NULL, "failed to create a listview window\n");
3430 item.mask = LVIF_STATE;
3431 item.stateMask = LVIS_SELECTED;
3432 item.state = LVIS_SELECTED;
3433 item.iItem = 0;
3434 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3435 expect(0, res);
3437 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3438 item.iItem = 0;
3439 item.pszText = buff;
3440 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3441 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3442 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3443 expect(TRUE, res);
3444 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3445 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3446 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3448 DestroyWindow(hwnd);
3451 static void test_nosortheader(void)
3453 HWND hwnd, header;
3454 LONG_PTR style;
3456 hwnd = create_listview_control(LVS_REPORT);
3457 ok(hwnd != NULL, "failed to create a listview window\n");
3459 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3460 ok(IsWindow(header), "header expected\n");
3462 style = GetWindowLongPtrA(header, GWL_STYLE);
3463 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3465 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3466 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3467 /* HDS_BUTTONS retained */
3468 style = GetWindowLongPtrA(header, GWL_STYLE);
3469 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3471 DestroyWindow(hwnd);
3473 /* create with LVS_NOSORTHEADER */
3474 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3475 ok(hwnd != NULL, "failed to create a listview window\n");
3477 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3478 ok(IsWindow(header), "header expected\n");
3480 style = GetWindowLongPtrA(header, GWL_STYLE);
3481 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3483 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3484 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3485 /* not changed here */
3486 style = GetWindowLongPtrA(header, GWL_STYLE);
3487 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3489 DestroyWindow(hwnd);
3492 static void test_setredraw(void)
3494 HWND hwnd;
3495 DWORD_PTR style;
3496 DWORD ret;
3497 HDC hdc;
3498 RECT rect;
3500 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3501 ok(hwnd != NULL, "failed to create a listview window\n");
3503 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3504 ListView seems to handle it internally without DefWinProc */
3506 /* default value first */
3507 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3508 expect(0, ret);
3509 /* disable */
3510 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3511 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3512 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3513 expect(0, ret);
3514 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3515 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3516 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3517 expect(0, ret);
3519 /* check update rect after redrawing */
3520 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3521 expect(0, ret);
3522 InvalidateRect(hwnd, NULL, FALSE);
3523 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3524 rect.right = rect.bottom = 1;
3525 GetUpdateRect(hwnd, &rect, FALSE);
3526 expect(0, rect.right);
3527 expect(0, rect.bottom);
3529 /* WM_ERASEBKGND */
3530 hdc = GetWindowDC(hwndparent);
3531 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3532 expect(TRUE, ret);
3533 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3534 expect(0, ret);
3535 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3536 expect(TRUE, ret);
3537 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3538 expect(0, ret);
3539 ReleaseDC(hwndparent, hdc);
3541 /* check notification messages to show that repainting is disabled */
3542 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3543 expect(TRUE, ret);
3544 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3545 expect(0, ret);
3546 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3548 InvalidateRect(hwnd, NULL, TRUE);
3549 UpdateWindow(hwnd);
3550 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3551 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3553 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3554 expect(TRUE, ret);
3555 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3556 InvalidateRect(hwnd, NULL, TRUE);
3557 UpdateWindow(hwnd);
3558 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3559 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3561 /* message isn't forwarded to header */
3562 subclass_header(hwnd);
3563 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3564 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3565 expect(0, ret);
3566 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3567 "WM_SETREDRAW: not forwarded to header", FALSE);
3569 DestroyWindow(hwnd);
3572 static void test_hittest(void)
3574 HWND hwnd;
3575 DWORD r;
3576 RECT bounds;
3577 LVITEMA item;
3578 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3579 POINT pos;
3580 INT x, y, i;
3581 WORD vert;
3582 HIMAGELIST himl, himl2;
3583 HBITMAP hbmp;
3585 hwnd = create_listview_control(LVS_REPORT);
3586 ok(hwnd != NULL, "failed to create a listview window\n");
3588 /* LVS_REPORT with a single subitem (2 columns) */
3589 insert_column(hwnd, 0);
3590 insert_column(hwnd, 1);
3591 insert_item(hwnd, 0);
3593 item.iSubItem = 0;
3594 /* the only purpose of that line is to be as long as a half item rect */
3595 item.pszText = text;
3596 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3597 expect(TRUE, r);
3599 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3600 expect(TRUE, r);
3601 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3602 expect(TRUE, r);
3604 memset(&bounds, 0, sizeof(bounds));
3605 bounds.left = LVIR_BOUNDS;
3606 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3607 expect(1, r);
3608 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3609 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3610 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3611 vert = HIWORD(r);
3612 ok(bounds.bottom - bounds.top == vert,
3613 "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3614 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3615 expect(TRUE, r);
3617 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3619 /* outside columns by x position - valid is [0, 199] */
3620 x = -1;
3621 y = pos.y + (bounds.bottom - bounds.top) / 2;
3622 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3623 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3625 x = pos.x + 50; /* column half width */
3626 y = pos.y + (bounds.bottom - bounds.top) / 2;
3627 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3628 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3629 x = pos.x + 150; /* outside column */
3630 y = pos.y + (bounds.bottom - bounds.top) / 2;
3631 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3632 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3633 y = (bounds.bottom - bounds.top) / 2;
3634 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3635 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3636 /* outside possible client rectangle (to right) */
3637 x = pos.x + 500;
3638 y = pos.y + (bounds.bottom - bounds.top) / 2;
3639 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3640 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3641 y = (bounds.bottom - bounds.top) / 2;
3642 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3643 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3644 /* subitem returned with -1 item too */
3645 x = pos.x + 150;
3646 y = bounds.top - vert;
3647 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3648 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3649 /* return values appear to underflow with negative indices */
3650 i = -2;
3651 y = y - vert;
3652 while (i > -10) {
3653 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3654 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3655 y = y - vert;
3656 i--;
3658 /* parent client area is 100x100 by default */
3659 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3660 x = pos.x + 150; /* outside column */
3661 y = pos.y + (bounds.bottom - bounds.top) / 2;
3662 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3663 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3664 y = (bounds.bottom - bounds.top) / 2;
3665 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3666 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3667 /* the same with LVS_EX_FULLROWSELECT */
3668 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3669 x = pos.x + 150; /* outside column */
3670 y = pos.y + (bounds.bottom - bounds.top) / 2;
3671 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3672 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3673 y = (bounds.bottom - bounds.top) / 2;
3674 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3675 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3676 x = pos.x + 150; /* outside column */
3677 y = pos.y + (bounds.bottom - bounds.top) / 2;
3678 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3679 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3680 y = (bounds.bottom - bounds.top) / 2;
3681 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3682 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3683 /* outside possible client rectangle (to right) */
3684 x = pos.x + 500;
3685 y = pos.y + (bounds.bottom - bounds.top) / 2;
3686 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3687 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3688 y = (bounds.bottom - bounds.top) / 2;
3689 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3690 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3691 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3692 himl = ImageList_Create(16, 16, 0, 4, 4);
3693 ok(himl != NULL, "failed to create imagelist\n");
3694 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3695 ok(hbmp != NULL, "failed to create bitmap\n");
3696 r = ImageList_Add(himl, hbmp, 0);
3697 ok(r == 0, "should be zero\n");
3698 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3699 ok(hbmp != NULL, "failed to create bitmap\n");
3700 r = ImageList_Add(himl, hbmp, 0);
3701 ok(r == 1, "should be one\n");
3703 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3704 expect(0, r);
3706 item.mask = LVIF_IMAGE;
3707 item.iImage = 0;
3708 item.iItem = 0;
3709 item.iSubItem = 0;
3710 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3711 expect(TRUE, r);
3712 /* on state icon */
3713 x = pos.x + 8;
3714 y = pos.y + (bounds.bottom - bounds.top) / 2;
3715 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3716 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3717 y = (bounds.bottom - bounds.top) / 2;
3718 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3720 /* state icons indices are 1 based, check with valid index */
3721 item.mask = LVIF_STATE;
3722 item.state = INDEXTOSTATEIMAGEMASK(1);
3723 item.stateMask = LVIS_STATEIMAGEMASK;
3724 item.iItem = 0;
3725 item.iSubItem = 0;
3726 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3727 expect(TRUE, r);
3728 /* on state icon */
3729 x = pos.x + 8;
3730 y = pos.y + (bounds.bottom - bounds.top) / 2;
3731 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3732 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3733 y = (bounds.bottom - bounds.top) / 2;
3734 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3736 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3737 ok(himl2 == himl, "should return handle\n");
3739 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3740 expect(0, r);
3741 /* on item icon */
3742 x = pos.x + 8;
3743 y = pos.y + (bounds.bottom - bounds.top) / 2;
3744 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3745 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3746 y = (bounds.bottom - bounds.top) / 2;
3747 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3749 DestroyWindow(hwnd);
3752 static void test_getviewrect(void)
3754 HWND hwnd;
3755 DWORD r;
3756 RECT rect;
3757 LVITEMA item;
3759 hwnd = create_listview_control(LVS_REPORT);
3760 ok(hwnd != NULL, "failed to create a listview window\n");
3762 /* empty */
3763 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3764 expect(TRUE, r);
3766 insert_column(hwnd, 0);
3767 insert_column(hwnd, 1);
3769 memset(&item, 0, sizeof(item));
3770 item.iItem = 0;
3771 item.iSubItem = 0;
3772 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3774 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3775 expect(TRUE, r);
3776 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3777 expect(TRUE, r);
3779 SetRect(&rect, -1, -1, -1, -1);
3780 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3781 expect(TRUE, r);
3782 /* left is set to (2e31-1) - XP SP2 */
3783 expect(0, rect.right);
3784 expect(0, rect.top);
3785 expect(0, rect.bottom);
3787 /* switch to LVS_ICON */
3788 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
3790 SetRect(&rect, -1, -1, -1, -1);
3791 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3792 expect(TRUE, r);
3793 expect(0, rect.left);
3794 expect(0, rect.top);
3795 /* precise value differs for 2k, XP and Vista */
3796 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3797 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3799 DestroyWindow(hwnd);
3802 static void test_getitemposition(void)
3804 HWND hwnd, header;
3805 DWORD r;
3806 POINT pt;
3807 RECT rect;
3809 hwnd = create_listview_control(LVS_REPORT);
3810 ok(hwnd != NULL, "failed to create a listview window\n");
3811 header = subclass_header(hwnd);
3813 /* LVS_REPORT, single item, no columns added */
3814 insert_item(hwnd, 0);
3816 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3818 pt.x = pt.y = -1;
3819 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3820 expect(TRUE, r);
3821 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3823 /* LVS_REPORT, single item, single column */
3824 insert_column(hwnd, 0);
3826 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3828 pt.x = pt.y = -1;
3829 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3830 expect(TRUE, r);
3831 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3833 memset(&rect, 0, sizeof(rect));
3834 SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3835 /* some padding? */
3836 expect(2, pt.x);
3837 /* offset by header height */
3838 expect(rect.bottom - rect.top, pt.y);
3840 DestroyWindow(hwnd);
3843 static void test_columnscreation(void)
3845 HWND hwnd, header;
3846 DWORD r;
3848 hwnd = create_listview_control(LVS_REPORT);
3849 ok(hwnd != NULL, "failed to create a listview window\n");
3851 insert_item(hwnd, 0);
3853 /* headers columns aren't created automatically */
3854 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3855 ok(IsWindow(header), "Expected header handle\n");
3856 r = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
3857 expect(0, r);
3859 DestroyWindow(hwnd);
3862 static void test_getitemrect(void)
3864 HWND hwnd;
3865 HIMAGELIST himl, himl_ret;
3866 HBITMAP hbm;
3867 RECT rect;
3868 DWORD r;
3869 LVITEMA item;
3870 LVCOLUMNA col;
3871 INT order[2];
3872 POINT pt;
3874 /* rectangle isn't empty for empty text items */
3875 hwnd = create_listview_control(LVS_LIST);
3876 memset(&item, 0, sizeof(item));
3877 item.mask = 0;
3878 item.iItem = 0;
3879 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3880 expect(0, r);
3881 rect.left = LVIR_LABEL;
3882 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3883 expect(TRUE, r);
3884 expect(0, rect.left);
3885 expect(0, rect.top);
3886 /* estimate it as width / height ratio */
3887 todo_wine
3888 ok((rect.right / rect.bottom) >= 5, "got right %d, bottom %d\n", rect.right, rect.bottom);
3889 DestroyWindow(hwnd);
3891 hwnd = create_listview_control(LVS_REPORT);
3892 ok(hwnd != NULL, "failed to create a listview window\n");
3894 /* empty item */
3895 memset(&item, 0, sizeof(item));
3896 item.iItem = 0;
3897 item.iSubItem = 0;
3898 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3899 expect(0, r);
3901 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3902 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3903 expect(TRUE, r);
3905 /* zero width rectangle with no padding */
3906 expect(0, rect.left);
3907 expect(0, rect.right);
3909 insert_column(hwnd, 0);
3910 insert_column(hwnd, 1);
3912 col.mask = LVCF_WIDTH;
3913 col.cx = 50;
3914 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
3915 expect(TRUE, r);
3917 col.mask = LVCF_WIDTH;
3918 col.cx = 100;
3919 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
3920 expect(TRUE, r);
3922 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3923 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3924 expect(TRUE, r);
3926 /* still no left padding */
3927 expect(0, rect.left);
3928 expect(150, rect.right);
3930 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
3931 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3932 expect(TRUE, r);
3933 /* padding */
3934 expect(2, rect.left);
3936 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
3937 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3938 expect(TRUE, r);
3939 /* padding, column width */
3940 expect(2, rect.left);
3941 expect(50, rect.right);
3943 /* no icons attached */
3944 SetRect(&rect, LVIR_ICON, -1, -1, -1);
3945 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3946 expect(TRUE, r);
3947 /* padding */
3948 expect(2, rect.left);
3949 expect(2, rect.right);
3951 /* change order */
3952 order[0] = 1; order[1] = 0;
3953 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3954 expect(TRUE, r);
3955 pt.x = -1;
3956 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3957 expect(TRUE, r);
3958 /* 1 indexed column width + padding */
3959 expect(102, pt.x);
3960 /* rect is at zero too */
3961 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3962 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3963 expect(TRUE, r);
3964 expect(0, rect.left);
3965 /* just width sum */
3966 expect(150, rect.right);
3968 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
3969 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3970 expect(TRUE, r);
3971 /* column width + padding */
3972 expect(102, rect.left);
3974 /* back to initial order */
3975 order[0] = 0; order[1] = 1;
3976 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3977 expect(TRUE, r);
3979 /* state icons */
3980 himl = ImageList_Create(16, 16, 0, 2, 2);
3981 ok(himl != NULL, "failed to create imagelist\n");
3982 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3983 ok(hbm != NULL, "failed to create bitmap\n");
3984 r = ImageList_Add(himl, hbm, 0);
3985 expect(0, r);
3986 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3987 ok(hbm != NULL, "failed to create bitmap\n");
3988 r = ImageList_Add(himl, hbm, 0);
3989 expect(1, r);
3991 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3992 expect(0, r);
3994 item.mask = LVIF_STATE;
3995 item.state = INDEXTOSTATEIMAGEMASK(1);
3996 item.stateMask = LVIS_STATEIMAGEMASK;
3997 item.iItem = 0;
3998 item.iSubItem = 0;
3999 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4000 expect(TRUE, r);
4002 /* icon bounds */
4003 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4004 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4005 expect(TRUE, r);
4006 /* padding + stateicon width */
4007 expect(18, rect.left);
4008 expect(18, rect.right);
4009 /* label bounds */
4010 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4011 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4012 expect(TRUE, r);
4013 /* padding + stateicon width -> column width */
4014 expect(18, rect.left);
4015 expect(50, rect.right);
4017 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4018 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4020 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4021 expect(0, r);
4023 item.mask = LVIF_STATE | LVIF_IMAGE;
4024 item.iImage = 1;
4025 item.state = 0;
4026 item.stateMask = ~0;
4027 item.iItem = 0;
4028 item.iSubItem = 0;
4029 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4030 expect(TRUE, r);
4032 /* icon bounds */
4033 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4034 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4035 expect(TRUE, r);
4036 /* padding, icon width */
4037 expect(2, rect.left);
4038 expect(18, rect.right);
4039 /* label bounds */
4040 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4041 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4042 expect(TRUE, r);
4043 /* padding + icon width -> column width */
4044 expect(18, rect.left);
4045 expect(50, rect.right);
4047 /* select bounds */
4048 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4049 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4050 expect(TRUE, r);
4051 /* padding, column width */
4052 expect(2, rect.left);
4053 expect(50, rect.right);
4055 /* try with indentation */
4056 item.mask = LVIF_INDENT;
4057 item.iIndent = 1;
4058 item.iItem = 0;
4059 item.iSubItem = 0;
4060 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4061 expect(TRUE, r);
4063 /* bounds */
4064 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4065 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4066 expect(TRUE, r);
4067 /* padding + 1 icon width, column width */
4068 expect(0, rect.left);
4069 expect(150, rect.right);
4071 /* select bounds */
4072 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4073 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4074 expect(TRUE, r);
4075 /* padding + 1 icon width, column width */
4076 expect(2 + 16, rect.left);
4077 expect(50, rect.right);
4079 /* label bounds */
4080 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4081 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4082 expect(TRUE, r);
4083 /* padding + 2 icon widths, column width */
4084 expect(2 + 16*2, rect.left);
4085 expect(50, rect.right);
4087 /* icon bounds */
4088 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4089 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4090 expect(TRUE, r);
4091 /* padding + 1 icon width indentation, icon width */
4092 expect(2 + 16, rect.left);
4093 expect(34, rect.right);
4095 DestroyWindow(hwnd);
4098 static void test_editbox(void)
4100 static CHAR testitemA[] = "testitem";
4101 static CHAR testitem1A[] = "testitem_quitelongname";
4102 static CHAR testitem2A[] = "testITEM_quitelongname";
4103 static CHAR buffer[25];
4104 HWND hwnd, hwndedit, hwndedit2, header;
4105 LVITEMA item;
4106 INT r;
4108 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4109 ok(hwnd != NULL, "failed to create a listview window\n");
4111 insert_column(hwnd, 0);
4113 memset(&item, 0, sizeof(item));
4114 item.mask = LVIF_TEXT;
4115 item.pszText = testitemA;
4116 item.iItem = 0;
4117 item.iSubItem = 0;
4118 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4119 expect(0, r);
4121 /* test notifications without edit created */
4122 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4123 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4124 expect(0, r);
4125 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4126 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4127 /* same thing but with valid window */
4128 hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4129 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4130 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4131 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4132 expect(0, r);
4133 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4134 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4135 DestroyWindow(hwndedit);
4137 /* setting focus is necessary */
4138 SetFocus(hwnd);
4139 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4140 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4142 /* test children Z-order after Edit box created */
4143 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4144 ok(IsWindow(header), "Expected header to be created\n");
4145 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4146 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4148 /* modify initial string */
4149 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4150 expect(TRUE, r);
4152 /* edit window is resized and repositioned,
4153 check again for Z-order - it should be preserved */
4154 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4155 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4157 /* return focus to listview */
4158 SetFocus(hwnd);
4160 memset(&item, 0, sizeof(item));
4161 item.mask = LVIF_TEXT;
4162 item.pszText = buffer;
4163 item.cchTextMax = sizeof(buffer);
4164 item.iItem = 0;
4165 item.iSubItem = 0;
4166 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4167 expect(TRUE, r);
4169 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4171 /* send LVM_EDITLABEL on already created edit */
4172 SetFocus(hwnd);
4173 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4174 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4175 /* focus will be set to edit */
4176 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4177 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4178 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4180 /* creating label disabled when control isn't focused */
4181 SetFocus(0);
4182 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4183 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4185 /* check EN_KILLFOCUS handling */
4186 memset(&item, 0, sizeof(item));
4187 item.pszText = testitemA;
4188 item.iItem = 0;
4189 item.iSubItem = 0;
4190 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4191 expect(TRUE, r);
4193 SetFocus(hwnd);
4194 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4195 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4196 /* modify edit and notify control that it lost focus */
4197 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4198 expect(TRUE, r);
4199 g_editbox_disp_info.item.pszText = NULL;
4200 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4201 expect(0, r);
4202 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4204 memset(&item, 0, sizeof(item));
4205 item.pszText = buffer;
4206 item.cchTextMax = sizeof(buffer);
4207 item.iItem = 0;
4208 item.iSubItem = 0;
4209 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4210 expect(lstrlenA(item.pszText), r);
4211 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4212 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4214 /* change item name to differ in casing only */
4215 SetFocus(hwnd);
4216 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4217 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4218 /* modify edit and notify control that it lost focus */
4219 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4220 expect(TRUE, r);
4221 g_editbox_disp_info.item.pszText = NULL;
4222 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4223 expect(0, r);
4224 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4226 memset(&item, 0, sizeof(item));
4227 item.pszText = buffer;
4228 item.cchTextMax = sizeof(buffer);
4229 item.iItem = 0;
4230 item.iSubItem = 0;
4231 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4232 expect(lstrlenA(item.pszText), r);
4233 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4234 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4236 /* end edit without saving */
4237 SetFocus(hwnd);
4238 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4239 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4240 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4241 expect(0, r);
4242 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4243 "edit box - end edit, no change, escape", TRUE);
4244 /* end edit with saving */
4245 SetFocus(hwnd);
4246 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4247 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4248 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4249 expect(0, r);
4250 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4251 "edit box - end edit, no change, return", TRUE);
4253 memset(&item, 0, sizeof(item));
4254 item.pszText = buffer;
4255 item.cchTextMax = sizeof(buffer);
4256 item.iItem = 0;
4257 item.iSubItem = 0;
4258 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4259 expect(lstrlenA(item.pszText), r);
4260 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4262 /* LVM_EDITLABEL with -1 destroys current edit */
4263 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4264 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4265 /* no edit present */
4266 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4267 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4268 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4269 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4270 /* edit present */
4271 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4272 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4273 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4274 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4275 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4276 /* check another negative value */
4277 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4278 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4279 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4280 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4281 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4282 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4283 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4284 /* and value greater than max item index */
4285 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4286 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4287 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4288 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4289 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4290 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4291 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4292 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4294 /* messaging tests */
4295 SetFocus(hwnd);
4296 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4297 blockEdit = FALSE;
4298 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4299 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4300 /* testing only sizing messages */
4301 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4302 "edit box create - sizing", FALSE);
4304 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4305 SetFocus(hwnd);
4306 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4307 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4308 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4309 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4310 expect(0, r);
4311 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4312 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4314 DestroyWindow(hwnd);
4317 static void test_notifyformat(void)
4319 HWND hwnd, header;
4320 DWORD r;
4322 hwnd = create_listview_control(LVS_REPORT);
4323 ok(hwnd != NULL, "failed to create a listview window\n");
4325 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4326 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4327 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4328 expect(0, r);
4329 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4330 /* set */
4331 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4332 expect(0, r);
4333 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4334 if (r == 1)
4336 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4337 expect(1, r);
4338 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4339 expect(0, r);
4341 else
4343 win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
4344 DestroyWindow(hwnd);
4345 return;
4348 DestroyWindow(hwnd);
4350 /* test failure in parent WM_NOTIFYFORMAT */
4351 notifyFormat = 0;
4352 hwnd = create_listview_control(LVS_REPORT);
4353 ok(hwnd != NULL, "failed to create a listview window\n");
4354 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4355 ok(IsWindow(header), "expected header to be created\n");
4356 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4357 expect(0, r);
4358 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4359 ok( r == 1, "Expected 1, got %d\n", r );
4360 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4361 ok(r != 0, "Expected valid format\n");
4363 notifyFormat = NFR_UNICODE;
4364 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4365 expect(NFR_UNICODE, r);
4366 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4367 expect(1, r);
4368 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4369 ok( r == 1, "Expected 1, got %d\n", r );
4371 notifyFormat = NFR_ANSI;
4372 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4373 expect(NFR_ANSI, r);
4374 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4375 expect(0, r);
4376 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4377 ok( r == 1, "Expected 1, got %d\n", r );
4379 DestroyWindow(hwnd);
4381 hwndparentW = create_parent_window(TRUE);
4382 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4383 if (!IsWindow(hwndparentW)) return;
4385 notifyFormat = -1;
4386 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4387 ok(hwnd != NULL, "failed to create a listview window\n");
4388 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4389 ok(IsWindow(header), "expected header to be created\n");
4390 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4391 expect(1, r);
4392 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4393 expect(1, r);
4394 DestroyWindow(hwnd);
4395 /* receiving error code defaulting to ansi */
4396 notifyFormat = 0;
4397 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4398 ok(hwnd != NULL, "failed to create a listview window\n");
4399 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4400 ok(IsWindow(header), "expected header to be created\n");
4401 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4402 expect(0, r);
4403 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4404 expect(1, r);
4405 DestroyWindow(hwnd);
4406 /* receiving ansi code from unicode window, use it */
4407 notifyFormat = NFR_ANSI;
4408 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4409 ok(hwnd != NULL, "failed to create a listview window\n");
4410 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4411 ok(IsWindow(header), "expected header to be created\n");
4412 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4413 expect(0, r);
4414 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4415 expect(1, r);
4416 DestroyWindow(hwnd);
4417 /* unicode listview with ansi parent window */
4418 notifyFormat = -1;
4419 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4420 ok(hwnd != NULL, "failed to create a listview window\n");
4421 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4422 ok(IsWindow(header), "expected header to be created\n");
4423 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4424 expect(0, r);
4425 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4426 expect(1, r);
4427 DestroyWindow(hwnd);
4428 /* unicode listview with ansi parent window, return error code */
4429 notifyFormat = 0;
4430 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4431 ok(hwnd != NULL, "failed to create a listview window\n");
4432 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4433 ok(IsWindow(header), "expected header to be created\n");
4434 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4435 expect(0, r);
4436 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4437 expect(1, r);
4438 DestroyWindow(hwnd);
4440 DestroyWindow(hwndparentW);
4443 static void test_indentation(void)
4445 HWND hwnd;
4446 LVITEMA item;
4447 DWORD r;
4449 hwnd = create_listview_control(LVS_REPORT);
4450 ok(hwnd != NULL, "failed to create a listview window\n");
4452 memset(&item, 0, sizeof(item));
4453 item.mask = LVIF_INDENT;
4454 item.iItem = 0;
4455 item.iIndent = I_INDENTCALLBACK;
4456 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4457 expect(0, r);
4459 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4461 item.iItem = 0;
4462 item.mask = LVIF_INDENT;
4463 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4464 expect(TRUE, r);
4466 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4467 "get indent dispinfo", FALSE);
4469 DestroyWindow(hwnd);
4472 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4474 return 0;
4477 static BOOL is_below_comctl_5(void)
4479 HWND hwnd;
4480 BOOL ret;
4482 hwnd = create_listview_control(LVS_REPORT);
4483 ok(hwnd != NULL, "failed to create a listview window\n");
4484 insert_item(hwnd, 0);
4486 ret = SendMessageA(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4488 DestroyWindow(hwnd);
4490 return !ret;
4493 static void test_get_set_view(void)
4495 HWND hwnd;
4496 DWORD ret;
4497 DWORD_PTR style;
4499 /* test style->view mapping */
4500 hwnd = create_listview_control(LVS_REPORT);
4501 ok(hwnd != NULL, "failed to create a listview window\n");
4503 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4504 expect(LV_VIEW_DETAILS, ret);
4506 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4507 /* LVS_ICON == 0 */
4508 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4509 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4510 expect(LV_VIEW_ICON, ret);
4512 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4513 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4514 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4515 expect(LV_VIEW_SMALLICON, ret);
4517 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4518 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4519 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4520 expect(LV_VIEW_LIST, ret);
4522 /* switching view doesn't touch window style */
4523 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4524 expect(1, ret);
4525 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4526 ok(style & LVS_LIST, "Expected style to be preserved\n");
4527 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4528 expect(1, ret);
4529 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4530 ok(style & LVS_LIST, "Expected style to be preserved\n");
4531 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4532 expect(1, ret);
4533 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4534 ok(style & LVS_LIST, "Expected style to be preserved\n");
4536 /* now change window style to see if view is remapped */
4537 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4538 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4539 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4540 expect(LV_VIEW_SMALLICON, ret);
4542 DestroyWindow(hwnd);
4545 static void test_canceleditlabel(void)
4547 HWND hwnd, hwndedit;
4548 DWORD ret;
4549 CHAR buff[10];
4550 LVITEMA itema;
4551 static CHAR test[] = "test";
4552 static const CHAR test1[] = "test1";
4554 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4555 ok(hwnd != NULL, "failed to create a listview window\n");
4557 insert_item(hwnd, 0);
4559 /* try without edit created */
4560 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4561 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4562 expect(TRUE, ret);
4563 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4564 "cancel edit label without edit", FALSE);
4566 /* cancel without data change */
4567 SetFocus(hwnd);
4568 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4569 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4570 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4571 expect(TRUE, ret);
4572 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4574 /* cancel after data change */
4575 memset(&itema, 0, sizeof(itema));
4576 itema.pszText = test;
4577 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4578 expect(TRUE, ret);
4579 SetFocus(hwnd);
4580 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4581 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4582 ret = SetWindowTextA(hwndedit, test1);
4583 expect(1, ret);
4584 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4585 expect(TRUE, ret);
4586 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4587 memset(&itema, 0, sizeof(itema));
4588 itema.pszText = buff;
4589 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
4590 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4591 expect(5, ret);
4592 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4594 DestroyWindow(hwnd);
4597 static void test_mapidindex(void)
4599 HWND hwnd;
4600 INT ret;
4602 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4603 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4604 ok(hwnd != NULL, "failed to create a listview window\n");
4605 insert_item(hwnd, 0);
4606 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4607 expect(-1, ret);
4608 DestroyWindow(hwnd);
4610 hwnd = create_listview_control(LVS_REPORT);
4611 ok(hwnd != NULL, "failed to create a listview window\n");
4613 /* LVM_MAPINDEXTOID with invalid index */
4614 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4615 expect(-1, ret);
4617 insert_item(hwnd, 0);
4618 insert_item(hwnd, 1);
4620 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4621 expect(-1, ret);
4622 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4623 expect(-1, ret);
4625 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4626 expect(0, ret);
4627 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4628 expect(1, ret);
4629 /* remove 0 indexed item, id retained */
4630 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4631 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4632 expect(1, ret);
4633 /* new id starts from previous value */
4634 insert_item(hwnd, 1);
4635 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4636 expect(2, ret);
4638 /* get index by id */
4639 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4640 expect(-1, ret);
4641 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4642 expect(-1, ret);
4643 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4644 expect(0, ret);
4645 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4646 expect(1, ret);
4648 DestroyWindow(hwnd);
4651 static void test_getitemspacing(void)
4653 HWND hwnd;
4654 DWORD ret;
4655 INT cx, cy;
4656 HIMAGELIST himl40, himl80;
4658 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4659 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4661 /* LVS_ICON */
4662 hwnd = create_listview_control(LVS_ICON);
4663 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4664 expect(cx, LOWORD(ret));
4665 expect(cy, HIWORD(ret));
4667 /* now try with icons */
4668 himl40 = ImageList_Create(40, 40, 0, 4, 4);
4669 ok(himl40 != NULL, "failed to create imagelist\n");
4670 himl80 = ImageList_Create(80, 80, 0, 4, 4);
4671 ok(himl80 != NULL, "failed to create imagelist\n");
4672 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4673 expect(0, ret);
4675 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4676 /* spacing + icon size returned */
4677 expect(cx + 40, LOWORD(ret));
4678 expect(cy + 40, HIWORD(ret));
4679 /* try changing icon size */
4680 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4682 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4683 /* spacing + icon size returned */
4684 expect(cx + 80, LOWORD(ret));
4685 expect(cy + 80, HIWORD(ret));
4687 /* set own icon spacing */
4688 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4689 expect(cx + 80, LOWORD(ret));
4690 expect(cy + 80, HIWORD(ret));
4692 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4693 /* set size returned */
4694 expect(100, LOWORD(ret));
4695 expect(100, HIWORD(ret));
4697 /* now change image list - icon spacing should be unaffected */
4698 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4700 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4701 /* set size returned */
4702 expect(100, LOWORD(ret));
4703 expect(100, HIWORD(ret));
4705 /* spacing = 0 - keep previous value */
4706 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
4707 expect(100, LOWORD(ret));
4708 expect(100, HIWORD(ret));
4710 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4711 expect(100, LOWORD(ret));
4713 expect(0xFFFF, HIWORD(ret));
4715 if (sizeof(void*) == 8)
4717 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
4718 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
4719 expect(100, LOWORD(ret));
4720 expect(0xFFFF, HIWORD(ret));
4722 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4723 expect(0xFFFF, LOWORD(ret));
4724 expect(0xFFFF, HIWORD(ret));
4726 else
4728 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4729 expect(100, LOWORD(ret));
4730 expect(0xFFFF, HIWORD(ret));
4732 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4733 /* spacing + icon size returned */
4734 expect(cx + 40, LOWORD(ret));
4735 expect(cy + 40, HIWORD(ret));
4737 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4738 ImageList_Destroy(himl80);
4739 DestroyWindow(hwnd);
4740 /* LVS_SMALLICON */
4741 hwnd = create_listview_control(LVS_SMALLICON);
4742 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4743 expect(cx, LOWORD(ret));
4744 expect(cy, HIWORD(ret));
4746 /* spacing does not depend on selected view type */
4747 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4748 expect(0, ret);
4750 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4751 /* spacing + icon size returned */
4752 expect(cx + 40, LOWORD(ret));
4753 expect(cy + 40, HIWORD(ret));
4755 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4756 ImageList_Destroy(himl40);
4757 DestroyWindow(hwnd);
4758 /* LVS_REPORT */
4759 hwnd = create_listview_control(LVS_REPORT);
4760 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4761 expect(cx, LOWORD(ret));
4762 expect(cy, HIWORD(ret));
4764 DestroyWindow(hwnd);
4765 /* LVS_LIST */
4766 hwnd = create_listview_control(LVS_LIST);
4767 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4768 expect(cx, LOWORD(ret));
4769 expect(cy, HIWORD(ret));
4771 DestroyWindow(hwnd);
4774 static INT get_current_font_height(HWND listview)
4776 TEXTMETRICA tm;
4777 HFONT hfont;
4778 HWND hwnd;
4779 HDC hdc;
4781 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
4782 if (!hwnd)
4783 hwnd = listview;
4785 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
4786 if (!hfont) {
4787 hdc = GetDC(hwnd);
4788 GetTextMetricsA(hdc, &tm);
4789 ReleaseDC(hwnd, hdc);
4791 else {
4792 HFONT oldfont;
4794 hdc = GetDC(0);
4795 oldfont = SelectObject(hdc, hfont);
4796 GetTextMetricsA(hdc, &tm);
4797 SelectObject(hdc, oldfont);
4798 ReleaseDC(0, hdc);
4801 return tm.tmHeight;
4804 static void test_getcolumnwidth(void)
4806 HWND hwnd;
4807 INT ret;
4808 DWORD_PTR style;
4809 LVCOLUMNA col;
4810 LVITEMA itema;
4811 INT height;
4813 /* default column width */
4814 hwnd = create_listview_control(LVS_ICON);
4815 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4816 expect(0, ret);
4817 style = GetWindowLongA(hwnd, GWL_STYLE);
4818 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
4819 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4820 todo_wine expect(8, ret);
4821 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
4822 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
4823 col.mask = 0;
4824 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4825 expect(0, ret);
4826 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4827 expect(10, ret);
4828 DestroyWindow(hwnd);
4830 /* default column width with item added */
4831 hwnd = create_listview_control(LVS_LIST);
4832 memset(&itema, 0, sizeof(itema));
4833 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4834 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4835 height = get_current_font_height(hwnd);
4836 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
4837 DestroyWindow(hwnd);
4840 static void test_scrollnotify(void)
4842 HWND hwnd;
4843 DWORD ret;
4845 hwnd = create_listview_control(LVS_REPORT);
4847 insert_column(hwnd, 0);
4848 insert_column(hwnd, 1);
4849 insert_item(hwnd, 0);
4851 /* make it scrollable - resize */
4852 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4853 expect(TRUE, ret);
4854 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4855 expect(TRUE, ret);
4857 /* try with dummy call */
4858 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4859 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
4860 expect(TRUE, ret);
4861 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4862 "scroll notify 1", TRUE);
4864 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4865 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
4866 expect(TRUE, ret);
4867 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4868 "scroll notify 2", TRUE);
4870 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4871 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
4872 expect(TRUE, ret);
4873 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4874 "scroll notify 3", TRUE);
4876 DestroyWindow(hwnd);
4879 static void test_LVS_EX_TRANSPARENTBKGND(void)
4881 HWND hwnd;
4882 DWORD ret;
4883 HDC hdc;
4885 hwnd = create_listview_control(LVS_REPORT);
4887 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4888 expect(TRUE, ret);
4890 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4891 LVS_EX_TRANSPARENTBKGND);
4893 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
4894 if (ret != CLR_NONE)
4896 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4897 DestroyWindow(hwnd);
4898 return;
4901 /* try to set some back color and check this style bit */
4902 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4903 expect(TRUE, ret);
4904 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4905 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4907 /* now test what this style actually does */
4908 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4909 LVS_EX_TRANSPARENTBKGND);
4911 hdc = GetWindowDC(hwndparent);
4913 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4914 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4915 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4916 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4918 ReleaseDC(hwndparent, hdc);
4920 DestroyWindow(hwnd);
4923 static void test_approximate_viewrect(void)
4925 HWND hwnd;
4926 DWORD ret;
4927 HIMAGELIST himl;
4928 HBITMAP hbmp;
4929 LVITEMA itema;
4930 static CHAR test[] = "abracadabra, a very long item label";
4932 hwnd = create_listview_control(LVS_ICON);
4933 himl = ImageList_Create(40, 40, 0, 4, 4);
4934 ok(himl != NULL, "failed to create imagelist\n");
4935 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4936 ok(hbmp != NULL, "failed to create bitmap\n");
4937 ret = ImageList_Add(himl, hbmp, 0);
4938 expect(0, ret);
4939 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4940 expect(0, ret);
4942 itema.mask = LVIF_IMAGE;
4943 itema.iImage = 0;
4944 itema.iItem = 0;
4945 itema.iSubItem = 0;
4946 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4947 expect(0, ret);
4949 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
4950 if (ret == 0)
4952 /* version 4.0 */
4953 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
4954 return;
4957 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4958 expect(MAKELONG(77,827), ret);
4960 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
4961 ok(ret != 0, "got 0\n");
4963 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4964 expect(MAKELONG(102,302), ret);
4966 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4967 expect(MAKELONG(52,52), ret);
4969 itema.pszText = test;
4970 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4971 expect(TRUE, ret);
4972 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4973 expect(MAKELONG(52,52), ret);
4975 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
4976 expect(MAKELONG(52,2), ret);
4977 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
4978 expect(MAKELONG(52,52), ret);
4979 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
4980 expect(MAKELONG(102,52), ret);
4981 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
4982 expect(MAKELONG(102,102), ret);
4983 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
4984 expect(MAKELONG(102,102), ret);
4985 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
4986 expect(MAKELONG(102,152), ret);
4987 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
4988 expect(MAKELONG(102,152), ret);
4989 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
4990 expect(MAKELONG(152,152), ret);
4992 DestroyWindow(hwnd);
4995 static void test_finditem(void)
4997 LVFINDINFOA fi;
4998 static char f[5];
4999 HWND hwnd;
5000 INT r;
5002 hwnd = create_listview_control(LVS_REPORT);
5003 insert_item(hwnd, 0);
5005 memset(&fi, 0, sizeof(fi));
5007 /* full string search, inserted text was "foo" */
5008 strcpy(f, "foo");
5009 fi.flags = LVFI_STRING;
5010 fi.psz = f;
5011 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5012 expect(0, r);
5013 /* partial string search, inserted text was "foo" */
5014 strcpy(f, "fo");
5015 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5016 fi.psz = f;
5017 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5018 expect(0, r);
5019 /* partial string search, part after start char */
5020 strcpy(f, "oo");
5021 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5022 fi.psz = f;
5023 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5024 expect(-1, r);
5026 /* try with LVFI_SUBSTRING */
5027 strcpy(f, "fo");
5028 fi.flags = LVFI_SUBSTRING;
5029 fi.psz = f;
5030 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5031 if (r == -1)
5033 win_skip("LVFI_SUBSTRING not supported\n");
5034 DestroyWindow(hwnd);
5035 return;
5037 expect(0, r);
5038 strcpy(f, "f");
5039 fi.flags = LVFI_SUBSTRING;
5040 fi.psz = f;
5041 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5042 expect(0, r);
5043 strcpy(f, "o");
5044 fi.flags = LVFI_SUBSTRING;
5045 fi.psz = f;
5046 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5047 expect(-1, r);
5049 strcpy(f, "f");
5050 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5051 fi.psz = f;
5052 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5053 expect(0, r);
5055 DestroyWindow(hwnd);
5058 static void test_LVS_EX_HEADERINALLVIEWS(void)
5060 HWND hwnd, header;
5061 DWORD style;
5063 hwnd = create_listview_control(LVS_ICON);
5065 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5066 LVS_EX_HEADERINALLVIEWS);
5068 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5069 if (!IsWindow(header))
5071 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5072 DestroyWindow(hwnd);
5073 return;
5076 /* LVS_NOCOLUMNHEADER works as before */
5077 style = GetWindowLongA(hwnd, GWL_STYLE);
5078 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5079 style = GetWindowLongA(header, GWL_STYLE);
5080 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5081 style = GetWindowLongA(hwnd, GWL_STYLE);
5082 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5083 style = GetWindowLongA(header, GWL_STYLE);
5084 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5086 /* try to remove style */
5087 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5088 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5089 ok(IsWindow(header), "Expected header to be created\n");
5090 style = GetWindowLongA(header, GWL_STYLE);
5091 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5093 DestroyWindow(hwnd);
5095 /* check other styles */
5096 hwnd = create_listview_control(LVS_LIST);
5097 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5098 LVS_EX_HEADERINALLVIEWS);
5099 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5100 ok(IsWindow(header), "Expected header to be created\n");
5101 DestroyWindow(hwnd);
5103 hwnd = create_listview_control(LVS_SMALLICON);
5104 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5105 LVS_EX_HEADERINALLVIEWS);
5106 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5107 ok(IsWindow(header), "Expected header to be created\n");
5108 DestroyWindow(hwnd);
5110 hwnd = create_listview_control(LVS_REPORT);
5111 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5112 LVS_EX_HEADERINALLVIEWS);
5113 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5114 ok(IsWindow(header), "Expected header to be created\n");
5115 DestroyWindow(hwnd);
5118 static void test_hover(void)
5120 HWND hwnd, fg;
5121 DWORD r;
5123 hwnd = create_listview_control(LVS_ICON);
5124 SetForegroundWindow(hwndparent);
5125 fg = GetForegroundWindow();
5126 if (fg != hwndparent)
5128 skip("Window is not in the foreground. Skipping hover tests.\n");
5129 DestroyWindow(hwnd);
5130 return;
5133 /* test WM_MOUSEHOVER forwarding */
5134 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5135 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5136 expect(0, r);
5137 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5138 g_block_hover = TRUE;
5139 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5140 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5141 expect(0, r);
5142 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5143 g_block_hover = FALSE;
5145 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5146 expect(HOVER_DEFAULT, r);
5147 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5148 expect(500, r);
5150 DestroyWindow(hwnd);
5153 static void test_destroynotify(void)
5155 HWND hwnd;
5156 BOOL ret;
5158 hwnd = create_listview_control(LVS_REPORT);
5159 ok(hwnd != NULL, "failed to create listview window\n");
5161 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5162 DestroyWindow(hwnd);
5163 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5165 /* same for ownerdata list */
5166 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5167 ok(hwnd != NULL, "failed to create listview window\n");
5169 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5170 DestroyWindow(hwnd);
5171 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5173 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5174 ok(hwnd != NULL, "failed to create listview window\n");
5176 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5177 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5178 ok(ret == TRUE, "got %d\n", ret);
5179 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5180 DestroyWindow(hwnd);
5183 static void test_header_notification(void)
5185 static char textA[] = "newtext";
5186 HWND list, header;
5187 HDITEMA item;
5188 NMHEADERA nmh;
5189 LVCOLUMNA col;
5190 DWORD ret;
5191 BOOL r;
5193 list = create_listview_control(LVS_REPORT);
5194 ok(list != NULL, "failed to create listview window\n");
5196 memset(&col, 0, sizeof(col));
5197 col.mask = LVCF_WIDTH;
5198 col.cx = 100;
5199 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5200 expect(0, ret);
5202 /* check list parent notification after header item changed,
5203 this test should be placed before header subclassing to avoid
5204 Listview -> Header messages to be logged */
5205 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5207 col.mask = LVCF_TEXT;
5208 col.pszText = textA;
5209 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5210 expect(TRUE, r);
5212 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5213 "header notify, listview", FALSE);
5214 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5215 "header notify, parent", FALSE);
5217 header = subclass_header(list);
5219 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5220 expect(1, ret);
5222 memset(&item, 0, sizeof(item));
5223 item.mask = HDI_WIDTH;
5224 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5225 expect(1, ret);
5226 expect(100, item.cxy);
5228 nmh.hdr.hwndFrom = header;
5229 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5230 nmh.hdr.code = HDN_ITEMCHANGEDA;
5231 nmh.iItem = 0;
5232 nmh.iButton = 0;
5233 item.mask = HDI_WIDTH;
5234 item.cxy = 50;
5235 nmh.pitem = &item;
5236 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5237 expect(0, ret);
5239 DestroyWindow(list);
5242 static void test_header_notification2(void)
5244 static char textA[] = "newtext";
5245 HWND list, header;
5246 HDITEMW itemW;
5247 NMHEADERW nmhdr;
5248 LVCOLUMNA col;
5249 DWORD ret;
5250 WCHAR buffer[100];
5251 struct message parent_header_notify_seq[] = {
5252 { WM_NOTIFY, sent|id, 0, 0, 0 },
5253 { 0 }
5256 list = create_listview_control(LVS_REPORT);
5257 ok(list != NULL, "failed to create listview window\n");
5259 memset(&col, 0, sizeof(col));
5260 col.mask = LVCF_WIDTH | LVCF_TEXT;
5261 col.cx = 100;
5262 col.pszText = textA;
5263 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5264 expect(0, ret);
5266 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5267 ok(header != 0, "No header\n");
5268 memset(&itemW, 0, sizeof(itemW));
5269 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5270 itemW.pszText = buffer;
5271 itemW.cchTextMax = sizeof(buffer);
5272 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5273 expect(1, ret);
5275 nmhdr.hdr.hwndFrom = header;
5276 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5277 nmhdr.iItem = 0;
5278 nmhdr.iButton = 0;
5279 nmhdr.pitem = &itemW;
5281 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5282 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5283 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5284 ok(ret == 0, "got %d\n", ret);
5285 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5286 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5287 "header notify, parent", TRUE);
5288 todo_wine
5289 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5290 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5291 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5292 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5293 ok(ret == 0, "got %d\n", ret);
5294 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5295 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5296 "header notify, parent", TRUE);
5297 todo_wine
5298 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5299 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5300 SetFocus(list);
5301 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5302 nmhdr.hdr.code = HDN_ITEMCLICKW;
5303 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5304 ok(ret == 0, "got %d\n", ret);
5305 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5306 "header notify, parent", FALSE);
5307 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5308 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5309 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5310 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5311 ok(ret == 0, "got %d\n", ret);
5312 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5313 "header notify, parent", FALSE);
5314 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5315 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5316 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5317 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5318 ok(ret == 0, "got %d\n", ret);
5319 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5320 "header notify, parent", TRUE);
5321 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5322 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5323 nmhdr.hdr.code = HDN_BEGINTRACKW;
5324 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5325 ok(ret == 0, "got %d\n", ret);
5326 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5327 "header notify, parent", FALSE);
5328 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5329 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5330 nmhdr.hdr.code = HDN_ENDTRACKW;
5331 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5332 ok(ret == 0, "got %d\n", ret);
5333 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5334 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5335 "header notify, parent", FALSE);
5336 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5337 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5338 nmhdr.hdr.code = HDN_TRACKW;
5339 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5340 ok(ret == 0, "got %d\n", ret);
5341 parent_header_notify_seq[0].id = HDN_TRACKA;
5342 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5343 "header notify, parent", FALSE);
5344 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5345 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5346 nmhdr.hdr.code = HDN_BEGINDRAG;
5347 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5348 ok(ret == 1, "got %d\n", ret);
5349 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5350 "header notify, parent", FALSE);
5351 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5352 nmhdr.hdr.code = HDN_ENDDRAG;
5353 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5354 ok(ret == 0, "got %d\n", ret);
5355 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5356 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5357 "header notify, parent", FALSE);
5358 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5359 nmhdr.hdr.code = HDN_FILTERCHANGE;
5360 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5361 ok(ret == 0, "got %d\n", ret);
5362 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5363 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5364 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5365 "header notify, parent", FALSE);
5366 parent_header_notify_seq[0].flags &= ~optional;
5367 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5368 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5369 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5370 ok(ret == 0, "got %d\n", ret);
5371 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5372 "header notify, parent", FALSE);
5373 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5374 nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5375 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5376 ok(ret == 0, "got %d\n", ret);
5377 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5378 "header notify, parent", FALSE);
5379 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5380 nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5381 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5382 ok(ret == 0, "got %d\n", ret);
5383 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5384 "header notify, parent", FALSE);
5385 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5386 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5387 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5388 ok(ret == 0, "got %d\n", ret);
5389 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5390 "header notify, parent", FALSE);
5392 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5394 DestroyWindow(list);
5397 static void test_createdragimage(void)
5399 HIMAGELIST himl;
5400 POINT pt;
5401 HWND list;
5403 list = create_listview_control(LVS_ICON);
5404 ok(list != NULL, "failed to create listview window\n");
5406 insert_item(list, 0);
5408 /* NULL point */
5409 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5410 ok(himl == NULL, "got %p\n", himl);
5412 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5413 ok(himl != NULL, "got %p\n", himl);
5414 ImageList_Destroy(himl);
5416 DestroyWindow(list);
5419 static void test_dispinfo(void)
5421 static const char testA[] = "TEST";
5422 WCHAR buff[10];
5423 LVITEMA item;
5424 HWND hwnd;
5425 DWORD ret;
5427 hwnd = create_listview_control(LVS_ICON);
5428 ok(hwnd != NULL, "failed to create listview window\n");
5430 insert_item(hwnd, 0);
5432 memset(&item, 0, sizeof(item));
5433 item.pszText = LPSTR_TEXTCALLBACKA;
5434 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5435 expect(1, ret);
5437 g_disp_A_to_W = TRUE;
5438 item.pszText = (char*)buff;
5439 item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
5440 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5441 ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
5442 g_disp_A_to_W = FALSE;
5444 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5445 "got %s, expected %s\n", item.pszText, testA);
5447 DestroyWindow(hwnd);
5450 static void test_LVM_SETITEMTEXT(void)
5452 static char testA[] = "TEST";
5453 LVITEMA item;
5454 HWND hwnd;
5455 DWORD ret;
5457 hwnd = create_listview_control(LVS_ICON);
5458 ok(hwnd != NULL, "failed to create listview window\n");
5460 insert_item(hwnd, 0);
5462 /* null item pointer */
5463 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5464 expect(FALSE, ret);
5466 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5467 expect(FALSE, ret);
5469 /* index out of bounds */
5470 item.pszText = testA;
5471 item.cchTextMax = 0; /* ignored */
5472 item.iSubItem = 0;
5474 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5475 expect(FALSE, ret);
5477 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5478 expect(FALSE, ret);
5480 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5481 expect(TRUE, ret);
5483 DestroyWindow(hwnd);
5486 static void test_imagelists(void)
5488 HWND hwnd, header;
5489 HIMAGELIST himl1, himl2, himl3;
5490 LRESULT ret;
5492 himl1 = ImageList_Create(40, 40, 0, 4, 4);
5493 himl2 = ImageList_Create(40, 40, 0, 4, 4);
5494 himl3 = ImageList_Create(40, 40, 0, 4, 4);
5495 ok(himl1 != NULL, "Failed to create imagelist\n");
5496 ok(himl2 != NULL, "Failed to create imagelist\n");
5497 ok(himl3 != NULL, "Failed to create imagelist\n");
5499 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5500 header = subclass_header(hwnd);
5502 ok(header != NULL, "Expected header\n");
5503 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5504 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5506 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5508 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5509 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5510 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5511 "set normal image list", FALSE);
5513 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5515 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5516 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5517 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5518 "set state image list", TRUE);
5520 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5521 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5523 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5525 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5526 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5527 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
5528 "set small image list", FALSE);
5530 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5531 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5532 DestroyWindow(hwnd);
5534 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
5536 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5538 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5539 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5540 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5541 "set normal image list", FALSE);
5543 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5545 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5546 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5547 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5548 "set state image list", FALSE);
5550 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5552 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5553 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5554 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5555 "set small image list", FALSE);
5557 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5558 ok(header == NULL, "Expected no header, got %p\n", header);
5560 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
5562 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5563 ok(header != NULL, "Expected header, got NULL\n");
5565 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5566 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5568 DestroyWindow(hwnd);
5571 static void test_deleteitem(void)
5573 LVITEMA item;
5574 UINT state;
5575 HWND hwnd;
5576 BOOL ret;
5578 hwnd = create_listview_control(LVS_REPORT);
5580 insert_item(hwnd, 0);
5581 insert_item(hwnd, 0);
5582 insert_item(hwnd, 0);
5583 insert_item(hwnd, 0);
5584 insert_item(hwnd, 0);
5586 g_focus_test_LVN_DELETEITEM = TRUE;
5588 /* delete focused item (not the last index) */
5589 item.stateMask = LVIS_FOCUSED;
5590 item.state = LVIS_FOCUSED;
5591 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
5592 ok(ret == TRUE, "got %d\n", ret);
5593 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
5594 ok(ret == TRUE, "got %d\n", ret);
5595 /* next item gets focus */
5596 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5597 ok(state == LVIS_FOCUSED, "got %x\n", state);
5599 /* focus last item and delete it */
5600 item.stateMask = LVIS_FOCUSED;
5601 item.state = LVIS_FOCUSED;
5602 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
5603 ok(ret == TRUE, "got %d\n", ret);
5604 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
5605 ok(ret == TRUE, "got %d\n", ret);
5606 /* new last item gets focus */
5607 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5608 ok(state == LVIS_FOCUSED, "got %x\n", state);
5610 /* focus first item and delete it */
5611 item.stateMask = LVIS_FOCUSED;
5612 item.state = LVIS_FOCUSED;
5613 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
5614 ok(ret == TRUE, "got %d\n", ret);
5615 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
5616 ok(ret == TRUE, "got %d\n", ret);
5617 /* new first item gets focus */
5618 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5619 ok(state == LVIS_FOCUSED, "got %x\n", state);
5621 g_focus_test_LVN_DELETEITEM = FALSE;
5623 DestroyWindow(hwnd);
5626 static void test_insertitem(void)
5628 LVITEMA item;
5629 UINT state;
5630 HWND hwnd;
5631 INT ret;
5633 hwnd = create_listview_control(LVS_REPORT);
5635 /* insert item 0 focused */
5636 item.mask = LVIF_STATE;
5637 item.state = LVIS_FOCUSED;
5638 item.stateMask = LVIS_FOCUSED;
5639 item.iItem = 0;
5640 item.iSubItem = 0;
5641 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5642 ok(ret == 0, "got %d\n", ret);
5644 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5645 ok(state == LVIS_FOCUSED, "got %x\n", state);
5647 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5649 /* insert item 1, focus shift */
5650 item.mask = LVIF_STATE;
5651 item.state = LVIS_FOCUSED;
5652 item.stateMask = LVIS_FOCUSED;
5653 item.iItem = 1;
5654 item.iSubItem = 0;
5655 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5656 ok(ret == 1, "got %d\n", ret);
5658 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
5660 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5661 ok(state == LVIS_FOCUSED, "got %x\n", state);
5663 /* insert item 2, no focus shift */
5664 item.mask = LVIF_STATE;
5665 item.state = 0;
5666 item.stateMask = LVIS_FOCUSED;
5667 item.iItem = 2;
5668 item.iSubItem = 0;
5669 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5670 ok(ret == 2, "got %d\n", ret);
5672 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5673 ok(state == LVIS_FOCUSED, "got %x\n", state);
5675 DestroyWindow(hwnd);
5678 static void test_header_proc(void)
5680 HWND hwnd, header, hdr;
5681 WNDPROC proc1, proc2;
5683 hwnd = create_listview_control(LVS_REPORT);
5685 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5686 ok(header != NULL, "got %p\n", header);
5688 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
5689 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
5690 0, 0, 0, 0,
5691 NULL, NULL, NULL, NULL);
5692 ok(hdr != NULL, "got %p\n", hdr);
5694 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
5695 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
5696 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
5698 DestroyWindow(hdr);
5699 DestroyWindow(hwnd);
5702 static void flush_events(void)
5704 MSG msg;
5705 int diff = 200;
5706 int min_timeout = 100;
5707 DWORD time = GetTickCount() + diff;
5709 while (diff > 0)
5711 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
5712 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
5713 diff = time - GetTickCount();
5717 static void test_oneclickactivate(void)
5719 TRACKMOUSEEVENT track;
5720 char item1[] = "item1";
5721 LVITEMA item;
5722 HWND hwnd, fg;
5723 RECT rect;
5724 INT r;
5726 hwnd = CreateWindowExA(0, "SysListView32", "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
5727 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
5728 ok(hwnd != NULL, "failed to create listview window\n");
5729 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
5730 ok(r == 0, "should return zero\n");
5732 SetForegroundWindow(hwndparent);
5733 flush_events();
5734 fg = GetForegroundWindow();
5735 if (fg != hwndparent)
5737 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
5738 DestroyWindow(hwnd);
5739 return;
5742 item.mask = LVIF_TEXT;
5743 item.iItem = 0;
5744 item.iSubItem = 0;
5745 item.iImage = 0;
5746 item.pszText = item1;
5747 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
5748 ok(r == 0, "should not fail\n");
5750 GetWindowRect(hwnd, &rect);
5751 SetCursorPos(rect.left+5, rect.top+5);
5752 flush_events();
5753 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
5754 expect(0, r);
5756 track.cbSize = sizeof(track);
5757 track.dwFlags = TME_QUERY;
5758 _TrackMouseEvent(&track);
5759 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
5760 ok(track.dwFlags == TME_LEAVE, "dwFlags = %x\n", track.dwFlags);
5762 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5763 expect(0, r);
5764 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
5765 expect(0, r);
5766 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5767 expect(1, r);
5769 DestroyWindow(hwnd);
5772 START_TEST(listview)
5774 HMODULE hComctl32;
5775 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
5777 ULONG_PTR ctx_cookie;
5778 HANDLE hCtx;
5780 hComctl32 = GetModuleHandleA("comctl32.dll");
5781 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
5782 if (pInitCommonControlsEx)
5784 INITCOMMONCONTROLSEX iccex;
5785 iccex.dwSize = sizeof(iccex);
5786 iccex.dwICC = ICC_LISTVIEW_CLASSES;
5787 pInitCommonControlsEx(&iccex);
5789 else
5790 InitCommonControls();
5792 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
5794 hwndparent = create_parent_window(FALSE);
5795 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5797 g_is_below_5 = is_below_comctl_5();
5799 test_header_notification();
5800 test_header_notification2();
5801 test_images();
5802 test_checkboxes();
5803 test_items();
5804 test_create();
5805 test_redraw();
5806 test_customdraw();
5807 test_icon_spacing();
5808 test_color();
5809 test_item_count();
5810 test_item_position();
5811 test_columns();
5812 test_getorigin();
5813 test_multiselect();
5814 test_getitemrect();
5815 test_subitem_rect();
5816 test_sorting();
5817 test_ownerdata();
5818 test_norecompute();
5819 test_nosortheader();
5820 test_setredraw();
5821 test_hittest();
5822 test_getviewrect();
5823 test_getitemposition();
5824 test_columnscreation();
5825 test_editbox();
5826 test_notifyformat();
5827 test_indentation();
5828 test_getitemspacing();
5829 test_getcolumnwidth();
5830 test_approximate_viewrect();
5831 test_finditem();
5832 test_hover();
5833 test_destroynotify();
5834 test_createdragimage();
5835 test_dispinfo();
5836 test_LVM_SETITEMTEXT();
5837 test_imagelists();
5838 test_deleteitem();
5839 test_insertitem();
5840 test_header_proc();
5841 test_oneclickactivate();
5843 if (!load_v6_module(&ctx_cookie, &hCtx))
5845 DestroyWindow(hwndparent);
5846 return;
5849 /* comctl32 version 6 tests start here */
5850 test_get_set_view();
5851 test_canceleditlabel();
5852 test_mapidindex();
5853 test_scrollnotify();
5854 test_LVS_EX_TRANSPARENTBKGND();
5855 test_LVS_EX_HEADERINALLVIEWS();
5856 test_deleteitem();
5857 test_multiselect();
5858 test_insertitem();
5859 test_header_proc();
5861 unload_v6_module(ctx_cookie, hCtx);
5863 DestroyWindow(hwndparent);