comctl32/tests: Extend PGM_SETCHILD tests.
[wine.git] / dlls / comctl32 / tests / listview.c
blob471f9f715c3d60bb3f9b406f6416889c6ccdfff1
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 if (IsWindowUnicode(hwnd))
559 ret = DefWindowProcW(hwnd, message, wParam, lParam);
560 else
561 ret = DefWindowProcA(hwnd, message, wParam, lParam);
562 defwndproc_counter--;
564 return ret;
567 static BOOL register_parent_wnd_class(BOOL Unicode)
569 WNDCLASSA clsA;
570 WNDCLASSW clsW;
572 if (Unicode)
574 clsW.style = 0;
575 clsW.lpfnWndProc = parent_wnd_proc;
576 clsW.cbClsExtra = 0;
577 clsW.cbWndExtra = 0;
578 clsW.hInstance = GetModuleHandleW(NULL);
579 clsW.hIcon = 0;
580 clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
581 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
582 clsW.lpszMenuName = NULL;
583 clsW.lpszClassName = testparentclassW;
585 else
587 clsA.style = 0;
588 clsA.lpfnWndProc = parent_wnd_proc;
589 clsA.cbClsExtra = 0;
590 clsA.cbWndExtra = 0;
591 clsA.hInstance = GetModuleHandleA(NULL);
592 clsA.hIcon = 0;
593 clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
594 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
595 clsA.lpszMenuName = NULL;
596 clsA.lpszClassName = "Listview test parent class";
599 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
602 static HWND create_parent_window(BOOL Unicode)
604 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
605 HWND hwnd;
607 if (!register_parent_wnd_class(Unicode))
608 return NULL;
610 blockEdit = FALSE;
611 notifyFormat = -1;
613 if (Unicode)
614 hwnd = CreateWindowExW(0, testparentclassW, nameW,
615 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
616 WS_MAXIMIZEBOX | WS_VISIBLE,
617 0, 0, 100, 100,
618 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
619 else
620 hwnd = CreateWindowExA(0, "Listview test parent class",
621 "Listview test parent window",
622 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
623 WS_MAXIMIZEBOX | WS_VISIBLE,
624 0, 0, 100, 100,
625 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
626 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
627 return hwnd;
630 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
632 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
633 static LONG defwndproc_counter = 0;
634 LRESULT ret;
635 struct message msg;
637 /* some debug output for style changing */
638 if ((message == WM_STYLECHANGING ||
639 message == WM_STYLECHANGED) && lParam)
641 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
642 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
645 msg.message = message;
646 msg.flags = sent|wparam|lparam;
647 if (defwndproc_counter) msg.flags |= defwinproc;
648 msg.wParam = wParam;
649 msg.lParam = lParam;
650 msg.id = LISTVIEW_ID;
651 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
652 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
654 defwndproc_counter++;
655 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
656 defwndproc_counter--;
657 return ret;
660 static HWND create_listview_control(DWORD style)
662 WNDPROC oldproc;
663 HWND hwnd;
664 RECT rect;
666 GetClientRect(hwndparent, &rect);
667 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
668 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
669 0, 0, rect.right, rect.bottom,
670 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
671 ok(hwnd != NULL, "gle=%d\n", GetLastError());
673 if (!hwnd) return NULL;
675 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
676 (LONG_PTR)listview_subclass_proc);
677 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
679 return hwnd;
682 /* unicode listview window with specified parent */
683 static HWND create_listview_controlW(DWORD style, HWND parent)
685 WNDPROC oldproc;
686 HWND hwnd;
687 RECT rect;
688 static const WCHAR nameW[] = {'f','o','o',0};
690 GetClientRect(parent, &rect);
691 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
692 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
693 0, 0, rect.right, rect.bottom,
694 parent, NULL, GetModuleHandleW(NULL), NULL);
695 ok(hwnd != NULL, "gle=%d\n", GetLastError());
697 if (!hwnd) return NULL;
699 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
700 (LONG_PTR)listview_subclass_proc);
701 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
703 return hwnd;
706 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
708 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
709 static LONG defwndproc_counter = 0;
710 struct message msg = { 0 };
711 LRESULT ret;
713 msg.message = message;
714 msg.flags = sent|wparam|lparam;
715 if (defwndproc_counter) msg.flags |= defwinproc;
716 msg.wParam = wParam;
717 msg.lParam = lParam;
718 msg.id = HEADER_ID;
719 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
721 defwndproc_counter++;
722 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
723 defwndproc_counter--;
724 return ret;
727 static HWND subclass_header(HWND hwndListview)
729 WNDPROC oldproc;
730 HWND hwnd;
732 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
733 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
734 (LONG_PTR)header_subclass_proc);
735 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
737 return hwnd;
740 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
742 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
743 static LONG defwndproc_counter = 0;
744 struct message msg = { 0 };
745 LRESULT ret;
747 msg.message = message;
748 msg.flags = sent|wparam|lparam;
749 if (defwndproc_counter) msg.flags |= defwinproc;
750 msg.wParam = wParam;
751 msg.lParam = lParam;
753 /* all we need is sizing */
754 if (message == WM_WINDOWPOSCHANGING ||
755 message == WM_NCCALCSIZE ||
756 message == WM_WINDOWPOSCHANGED ||
757 message == WM_MOVE ||
758 message == WM_SIZE)
760 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
763 defwndproc_counter++;
764 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
765 defwndproc_counter--;
766 return ret;
769 static HWND subclass_editbox(HWND hwndListview)
771 WNDPROC oldproc;
772 HWND hwnd;
774 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
775 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
776 (LONG_PTR)editbox_subclass_proc);
777 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
779 return hwnd;
782 /* Performs a single LVM_HITTEST test */
783 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
784 BOOL todo_item, BOOL todo_flags, int line)
786 LVHITTESTINFO lpht;
787 INT ret;
789 lpht.pt.x = x;
790 lpht.pt.y = y;
791 lpht.iSubItem = 10;
793 ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
795 todo_wine_if(todo_item)
797 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
798 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
799 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
802 if (todo_flags)
804 todo_wine
805 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
807 else if (broken_flags)
808 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
809 "Expected flags %x, got %x\n", flags, lpht.flags);
810 else
811 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
814 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
816 /* Performs a single LVM_SUBITEMHITTEST test */
817 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
818 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
820 LVHITTESTINFO lpht;
821 INT ret;
823 lpht.pt.x = x;
824 lpht.pt.y = y;
826 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
828 todo_wine_if(todo_item)
830 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
831 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
834 todo_wine_if(todo_subitem)
835 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
837 todo_wine_if(todo_flags)
838 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
841 #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__)
843 static void test_images(void)
845 HWND hwnd;
846 INT r;
847 LVITEMA item;
848 HIMAGELIST himl;
849 HBITMAP hbmp;
850 RECT r1, r2;
851 static CHAR hello[] = "hello";
853 himl = ImageList_Create(40, 40, 0, 4, 4);
854 ok(himl != NULL, "failed to create imagelist\n");
856 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
857 ok(hbmp != NULL, "failed to create bitmap\n");
859 r = ImageList_Add(himl, hbmp, 0);
860 ok(r == 0, "should be zero\n");
862 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
863 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
864 ok(hwnd != NULL, "failed to create listview window\n");
866 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
867 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
869 ok(r == 0, "should return zero\n");
871 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
872 ok(r == 0, "should return zero\n");
874 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
875 ok(r != 0, "got 0\n");
877 /* returns dimensions */
879 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
880 ok(r == 0, "should be zero items\n");
882 item.mask = LVIF_IMAGE | LVIF_TEXT;
883 item.iItem = 0;
884 item.iSubItem = 1;
885 item.iImage = 0;
886 item.pszText = 0;
887 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
888 ok(r == -1, "should fail\n");
890 item.iSubItem = 0;
891 item.pszText = hello;
892 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
893 ok(r == 0, "should not fail\n");
895 SetRect(&r1, LVIR_ICON, 0, 0, 0);
896 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
897 expect(1, r);
899 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
900 ok(r == TRUE, "should not fail\n");
902 item.iSubItem = 0;
903 item.pszText = hello;
904 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
905 ok(r == 0, "should not fail\n");
907 SetRect(&r2, LVIR_ICON, 0, 0, 0);
908 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
909 expect(1, r);
911 ok(EqualRect(&r1, &r2), "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 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1185 ok(r, "got %d\n", r);
1187 /* LVIS_SELECTED with zero stateMask */
1188 /* set */
1189 memset (&item, 0, sizeof (item));
1190 item.mask = LVIF_STATE;
1191 item.state = LVIS_FOCUSED;
1192 item.stateMask = 0;
1193 item.iItem = 0;
1194 item.iSubItem = 0;
1195 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1196 expect(0, r);
1197 /* get */
1198 memset (&item, 0xcc, sizeof (item));
1199 item.mask = LVIF_STATE;
1200 item.stateMask = LVIS_FOCUSED;
1201 item.state = 0;
1202 item.iItem = 0;
1203 item.iSubItem = 0;
1204 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1205 expect(1, r);
1206 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1207 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1208 ok(r, "got %d\n", r);
1210 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1211 /* set */
1212 memset (&item, 0, sizeof (item));
1213 item.mask = LVIF_STATE;
1214 item.state = LVIS_CUT;
1215 item.stateMask = LVIS_FOCUSED;
1216 item.iItem = 0;
1217 item.iSubItem = 0;
1218 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1219 expect(0, r);
1220 /* get */
1221 memset (&item, 0xcc, sizeof (item));
1222 item.mask = LVIF_STATE;
1223 item.stateMask = LVIS_CUT;
1224 item.state = 0;
1225 item.iItem = 0;
1226 item.iSubItem = 0;
1227 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1228 expect(1, r);
1229 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1230 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1231 ok(r, "got %d\n", r);
1233 /* Insert an item with just a param */
1234 memset (&item, 0xcc, sizeof (item));
1235 item.mask = LVIF_PARAM;
1236 item.iItem = 0;
1237 item.iSubItem = 0;
1238 item.lParam = lparamTest;
1239 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1240 expect(0, r);
1242 /* Test getting of the param */
1243 memset (&item, 0xcc, sizeof (item));
1244 item.mask = LVIF_PARAM;
1245 item.iItem = 0;
1246 item.iSubItem = 0;
1247 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1248 expect(1, r);
1249 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1251 /* Set up a subitem */
1252 memset (&item, 0xcc, sizeof (item));
1253 item.mask = LVIF_TEXT;
1254 item.iItem = 0;
1255 item.iSubItem = 1;
1256 item.pszText = text;
1257 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1258 expect(1, r);
1260 item.mask = LVIF_TEXT;
1261 item.iItem = 0;
1262 item.iSubItem = 1;
1263 item.pszText = buffA;
1264 item.cchTextMax = sizeof(buffA);
1265 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1266 expect(1, r);
1267 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1269 /* set up with extra flag */
1270 /* 1. reset subitem text */
1271 item.mask = LVIF_TEXT;
1272 item.iItem = 0;
1273 item.iSubItem = 1;
1274 item.pszText = NULL;
1275 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1276 expect(1, r);
1278 item.mask = LVIF_TEXT;
1279 item.iItem = 0;
1280 item.iSubItem = 1;
1281 item.pszText = buffA;
1282 buffA[0] = 'a';
1283 item.cchTextMax = sizeof(buffA);
1284 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1285 expect(1, r);
1286 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1288 /* 2. set new text with extra flag specified */
1289 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1290 item.iItem = 0;
1291 item.iSubItem = 1;
1292 item.pszText = text;
1293 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1294 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1296 if (r == 1)
1298 item.mask = LVIF_TEXT;
1299 item.iItem = 0;
1300 item.iSubItem = 1;
1301 item.pszText = buffA;
1302 buffA[0] = 'a';
1303 item.cchTextMax = sizeof(buffA);
1304 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1305 expect(1, r);
1306 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1309 /* Query param from subitem: returns main item param */
1310 memset (&item, 0xcc, sizeof (item));
1311 item.mask = LVIF_PARAM;
1312 item.iItem = 0;
1313 item.iSubItem = 1;
1314 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1315 expect(1, r);
1316 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1318 /* Set up param on first subitem: no effect */
1319 memset (&item, 0xcc, sizeof (item));
1320 item.mask = LVIF_PARAM;
1321 item.iItem = 0;
1322 item.iSubItem = 1;
1323 item.lParam = lparamTest+1;
1324 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1325 expect(0, r);
1327 /* Query param from subitem again: should still return main item param */
1328 memset (&item, 0xcc, sizeof (item));
1329 item.mask = LVIF_PARAM;
1330 item.iItem = 0;
1331 item.iSubItem = 1;
1332 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1333 expect(1, r);
1334 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1336 /**** Some tests of state highlighting ****/
1337 memset (&item, 0xcc, sizeof (item));
1338 item.mask = LVIF_STATE;
1339 item.iItem = 0;
1340 item.iSubItem = 0;
1341 item.state = LVIS_SELECTED;
1342 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1343 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1344 expect(1, r);
1345 item.iSubItem = 1;
1346 item.state = LVIS_DROPHILITED;
1347 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1348 expect(1, r);
1350 memset (&item, 0xcc, sizeof (item));
1351 item.mask = LVIF_STATE;
1352 item.iItem = 0;
1353 item.iSubItem = 0;
1354 item.stateMask = -1;
1355 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1356 expect(1, r);
1357 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1358 item.iSubItem = 1;
1359 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1360 expect(1, r);
1361 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1363 /* some notnull but meaningless masks */
1364 memset (&item, 0, sizeof(item));
1365 item.mask = LVIF_NORECOMPUTE;
1366 item.iItem = 0;
1367 item.iSubItem = 0;
1368 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1369 expect(1, r);
1370 memset (&item, 0, sizeof(item));
1371 item.mask = LVIF_DI_SETITEM;
1372 item.iItem = 0;
1373 item.iSubItem = 0;
1374 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1375 expect(1, r);
1377 /* set text to callback value already having it */
1378 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1379 expect(TRUE, r);
1380 memset (&item, 0, sizeof (item));
1381 item.mask = LVIF_TEXT;
1382 item.pszText = LPSTR_TEXTCALLBACKA;
1383 item.iItem = 0;
1384 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1385 expect(0, r);
1386 memset (&item, 0, sizeof (item));
1388 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1390 item.pszText = LPSTR_TEXTCALLBACKA;
1391 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1392 expect(TRUE, r);
1394 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1395 "check callback text comparison rule", FALSE);
1397 DestroyWindow(hwnd);
1400 static void test_columns(void)
1402 HWND hwnd, header;
1403 LVCOLUMNA column;
1404 LVITEMA item;
1405 INT order[2];
1406 CHAR buff[5];
1407 DWORD rc;
1409 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_LIST,
1410 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1411 ok(hwnd != NULL, "failed to create listview window\n");
1413 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1414 ok(header == NULL, "got %p\n", header);
1416 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1417 ok(rc == 0, "got %d\n", rc);
1419 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1420 ok(header == NULL, "got %p\n", header);
1422 DestroyWindow(hwnd);
1424 hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1425 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1426 ok(hwnd != NULL, "failed to create listview window\n");
1428 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, -1, 0);
1429 ok(!rc, "got %d\n", rc);
1431 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, 0, 0);
1432 ok(!rc, "got %d\n", rc);
1434 /* Add a column with no mask */
1435 memset(&column, 0xcc, sizeof(column));
1436 column.mask = 0;
1437 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1438 ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1440 /* Check its width */
1441 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1442 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1444 DestroyWindow(hwnd);
1446 /* LVM_GETCOLUMNORDERARRAY */
1447 hwnd = create_listview_control(LVS_REPORT);
1448 subclass_header(hwnd);
1450 memset(&column, 0, sizeof(column));
1451 column.mask = LVCF_WIDTH;
1452 column.cx = 100;
1453 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1454 expect(0, rc);
1456 column.cx = 200;
1457 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1458 expect(1, rc);
1460 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1462 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1463 expect(1, rc);
1464 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1465 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1467 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1468 expect(0, rc);
1470 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1472 /* LVM_SETCOLUMNORDERARRAY */
1473 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1475 order[0] = 0;
1476 order[1] = 1;
1477 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1478 expect(1, rc);
1480 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1481 expect(0, rc);
1483 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1485 /* after column added subitem is considered as present */
1486 insert_item(hwnd, 0);
1488 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1490 item.pszText = buff;
1491 item.cchTextMax = sizeof(buff);
1492 item.iItem = 0;
1493 item.iSubItem = 1;
1494 item.mask = LVIF_TEXT;
1495 memset(&g_itema, 0, sizeof(g_itema));
1496 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1497 expect(1, rc);
1498 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1500 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1501 "get subitem text after column added", FALSE);
1503 DestroyWindow(hwnd);
1506 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1507 static WNDPROC listviewWndProc;
1508 static HIMAGELIST test_create_imagelist;
1510 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1512 LRESULT ret;
1514 if (uMsg == WM_CREATE)
1516 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1517 lpcs->style |= LVS_REPORT;
1519 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1520 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1521 return ret;
1524 static void test_create(void)
1526 HWND hList;
1527 HWND hHeader;
1528 LONG_PTR ret;
1529 LONG r;
1530 LVCOLUMNA col;
1531 RECT rect;
1532 WNDCLASSEXA cls;
1533 DWORD style;
1535 cls.cbSize = sizeof(WNDCLASSEXA);
1536 ok(GetClassInfoExA(GetModuleHandleA(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1537 listviewWndProc = cls.lpfnWndProc;
1538 cls.lpfnWndProc = create_test_wndproc;
1539 cls.lpszClassName = "MyListView32";
1540 ok(RegisterClassExA(&cls), "RegisterClassEx failed\n");
1542 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1543 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1544 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1545 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1547 if (!IsWindow(hHeader))
1549 /* version 4.0 */
1550 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1551 DestroyWindow(hList);
1552 return;
1555 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1556 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1557 DestroyWindow(hList);
1559 /* header isn't created on LVS_ICON and LVS_LIST styles */
1560 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1561 GetModuleHandleA(NULL), 0);
1562 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1563 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1564 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1565 /* insert column */
1566 memset(&col, 0, sizeof(LVCOLUMNA));
1567 col.mask = LVCF_WIDTH;
1568 col.cx = 100;
1569 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1570 expect(0, r);
1571 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1572 ok(IsWindow(hHeader), "Header should be created\n");
1573 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1574 style = GetWindowLongA(hHeader, GWL_STYLE);
1575 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1576 DestroyWindow(hList);
1578 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1579 GetModuleHandleA(NULL), 0);
1580 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1581 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1582 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1583 /* insert column */
1584 memset(&col, 0, sizeof(LVCOLUMNA));
1585 col.mask = LVCF_WIDTH;
1586 col.cx = 100;
1587 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1588 expect(0, r);
1589 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1590 ok(IsWindow(hHeader), "Header should be created\n");
1591 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1592 DestroyWindow(hList);
1594 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1595 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1596 GetModuleHandleA(NULL), 0);
1597 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1598 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1599 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1600 ok(IsWindow(hHeader), "Header should be created\n");
1601 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1602 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1603 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1604 ok(IsWindow(hHeader), "Header should be created\n");
1605 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1606 DestroyWindow(hList);
1608 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1609 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1610 GetModuleHandleA(NULL), 0);
1611 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1612 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1613 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1614 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1615 ok(IsWindow(hHeader), "Header should be created\n");
1616 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1617 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1618 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1619 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1620 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1621 ok(IsWindow(hHeader), "Header should be created\n");
1622 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1623 DestroyWindow(hList);
1625 /* LVS_REPORT without WS_VISIBLE */
1626 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1627 GetModuleHandleA(NULL), 0);
1628 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1629 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1630 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1631 /* insert column */
1632 memset(&col, 0, sizeof(LVCOLUMNA));
1633 col.mask = LVCF_WIDTH;
1634 col.cx = 100;
1635 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1636 expect(0, r);
1637 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1638 ok(IsWindow(hHeader), "Header should be created\n");
1639 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1640 DestroyWindow(hList);
1642 /* LVS_REPORT without WS_VISIBLE, try to show it */
1643 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1644 GetModuleHandleA(NULL), 0);
1645 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1646 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1647 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1648 ShowWindow(hList, SW_SHOW);
1649 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1650 ok(IsWindow(hHeader), "Header should be created\n");
1651 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1652 DestroyWindow(hList);
1654 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1655 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1656 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1657 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1658 ok(IsWindow(hHeader), "Header should be created\n");
1659 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1660 /* HDS_DRAGDROP set by default */
1661 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1662 DestroyWindow(hList);
1664 /* setting LVS_EX_HEADERDRAGDROP creates header */
1665 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1666 GetModuleHandleA(NULL), 0);
1667 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1668 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1669 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1670 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1671 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1672 ok(IsWindow(hHeader) ||
1673 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1674 "Header should be created\n");
1675 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1676 DestroyWindow(hList);
1678 /* setting LVS_EX_GRIDLINES creates header */
1679 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1680 GetModuleHandleA(NULL), 0);
1681 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1682 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1683 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1684 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1685 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1686 ok(IsWindow(hHeader) ||
1687 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1688 "Header should be created\n");
1689 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1690 DestroyWindow(hList);
1692 /* setting LVS_EX_FULLROWSELECT creates header */
1693 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1694 GetModuleHandleA(NULL), 0);
1695 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1696 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1697 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1698 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1699 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1700 ok(IsWindow(hHeader) ||
1701 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1702 "Header should be created\n");
1703 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1704 DestroyWindow(hList);
1706 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1707 hList = create_listview_control(LVS_ICON);
1708 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1709 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1710 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1711 DestroyWindow(hList);
1713 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1714 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1715 GetModuleHandleA(NULL), 0);
1716 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1717 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1719 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1720 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1721 /* right value contains garbage, probably because header columns are not set up */
1722 expect(0, rect.bottom);
1723 expect(1, r);
1725 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1726 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1727 ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1729 DestroyWindow(hList);
1731 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1732 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1733 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1734 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1735 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1736 DestroyWindow(hList);
1739 static void test_redraw(void)
1741 HWND hwnd;
1742 HDC hdc;
1743 BOOL res;
1744 DWORD r;
1746 hwnd = create_listview_control(LVS_REPORT);
1747 subclass_header(hwnd);
1749 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1751 InvalidateRect(hwnd, NULL, TRUE);
1752 UpdateWindow(hwnd);
1753 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1755 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1757 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1758 /* 1. Without backbuffer */
1759 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1760 expect(TRUE, res);
1762 hdc = GetWindowDC(hwndparent);
1764 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1765 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1766 ok(r == 1, "Expected not zero result\n");
1767 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1768 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1770 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1771 expect(TRUE, res);
1773 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1774 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1775 expect(1, r);
1776 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1777 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1779 /* 2. With backbuffer */
1780 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1781 LVS_EX_DOUBLEBUFFER);
1782 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1783 expect(TRUE, res);
1785 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1786 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1787 expect(1, r);
1788 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1789 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1791 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1792 expect(TRUE, res);
1794 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1795 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1796 todo_wine expect(1, r);
1797 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1798 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1800 ReleaseDC(hwndparent, hdc);
1802 DestroyWindow(hwnd);
1805 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1807 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1809 if(message == WM_NOTIFY) {
1810 NMHDR *nmhdr = (NMHDR*)lParam;
1811 if(nmhdr->code == NM_CUSTOMDRAW) {
1812 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1813 struct message msg;
1815 msg.message = message;
1816 msg.flags = sent|wparam|lparam|custdraw;
1817 msg.wParam = wParam;
1818 msg.lParam = lParam;
1819 msg.id = nmhdr->code;
1820 msg.stage = nmlvcd->nmcd.dwDrawStage;
1821 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1823 switch(nmlvcd->nmcd.dwDrawStage) {
1824 case CDDS_PREPAINT:
1825 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1826 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1827 case CDDS_ITEMPREPAINT:
1828 nmlvcd->clrTextBk = CLR_DEFAULT;
1829 nmlvcd->clrText = RGB(0, 255, 0);
1830 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1831 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1832 clr = GetBkColor(nmlvcd->nmcd.hdc);
1833 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1834 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1835 todo_wine_if(nmlvcd->iSubItem)
1836 ok(clr == c0ffee, "clr=%.8x\n", clr);
1837 return CDRF_NOTIFYPOSTPAINT;
1838 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1839 clr = GetBkColor(nmlvcd->nmcd.hdc);
1840 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1841 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1842 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1843 return CDRF_DODEFAULT;
1845 return CDRF_DODEFAULT;
1849 return DefWindowProcA(hwnd, message, wParam, lParam);
1852 static void test_customdraw(void)
1854 HWND hwnd;
1855 WNDPROC oldwndproc;
1857 hwnd = create_listview_control(LVS_REPORT);
1859 insert_column(hwnd, 0);
1860 insert_column(hwnd, 1);
1861 insert_item(hwnd, 0);
1863 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
1864 (LONG_PTR)cd_wndproc);
1866 InvalidateRect(hwnd, NULL, TRUE);
1867 UpdateWindow(hwnd);
1869 /* message tests */
1870 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1871 InvalidateRect(hwnd, NULL, TRUE);
1872 UpdateWindow(hwnd);
1873 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1875 DestroyWindow(hwnd);
1877 hwnd = create_listview_control(LVS_LIST);
1879 insert_column(hwnd, 0);
1880 insert_column(hwnd, 1);
1881 insert_item(hwnd, 0);
1883 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1884 InvalidateRect(hwnd, NULL, TRUE);
1885 UpdateWindow(hwnd);
1886 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1888 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1889 DestroyWindow(hwnd);
1892 static void test_icon_spacing(void)
1894 /* LVM_SETICONSPACING */
1895 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1897 HWND hwnd;
1898 WORD w, h;
1899 INT r;
1901 hwnd = create_listview_control(LVS_ICON);
1902 ok(hwnd != NULL, "failed to create a listview window\n");
1904 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1905 expect(NFR_ANSI, r);
1907 /* reset the icon spacing to defaults */
1908 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1910 /* now we can request what the defaults are */
1911 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1912 w = LOWORD(r);
1913 h = HIWORD(r);
1915 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1917 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1918 ok(r == MAKELONG(w, h) ||
1919 broken(r == MAKELONG(w, w)), /* win98 */
1920 "Expected %d, got %d\n", MAKELONG(w, h), r);
1922 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1923 if (r == 0)
1925 /* version 4.0 */
1926 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1927 DestroyWindow(hwnd);
1928 return;
1930 expect(MAKELONG(20,30), r);
1932 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1933 expect(MAKELONG(25,35), r);
1935 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1937 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1938 DestroyWindow(hwnd);
1941 static void test_color(void)
1943 RECT rect;
1944 HWND hwnd;
1945 DWORD r;
1946 int i;
1948 COLORREF color;
1949 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1951 hwnd = create_listview_control(LVS_REPORT);
1952 ok(hwnd != NULL, "failed to create a listview window\n");
1954 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1956 for (i = 0; i < 4; i++)
1958 color = colors[i];
1960 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
1961 expect(TRUE, r);
1962 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
1963 expect(color, r);
1965 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
1966 expect (TRUE, r);
1967 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1968 expect(color, r);
1970 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1971 expect(TRUE, r);
1972 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1973 expect(color, r);
1976 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1977 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1979 /* invalidation test done separately to avoid a message chain mess */
1980 r = ValidateRect(hwnd, NULL);
1981 expect(TRUE, r);
1982 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
1983 expect(TRUE, r);
1985 rect.right = rect.bottom = 1;
1986 r = GetUpdateRect(hwnd, &rect, TRUE);
1987 todo_wine expect(FALSE, r);
1988 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1990 r = ValidateRect(hwnd, NULL);
1991 expect(TRUE, r);
1992 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
1993 expect(TRUE, r);
1995 rect.right = rect.bottom = 1;
1996 r = GetUpdateRect(hwnd, &rect, TRUE);
1997 todo_wine expect(FALSE, r);
1998 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2000 r = ValidateRect(hwnd, NULL);
2001 expect(TRUE, r);
2002 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2003 expect(TRUE, r);
2005 rect.right = rect.bottom = 1;
2006 r = GetUpdateRect(hwnd, &rect, TRUE);
2007 todo_wine expect(FALSE, r);
2008 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2010 DestroyWindow(hwnd);
2013 static void test_item_count(void)
2015 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2017 HWND hwnd;
2018 DWORD r;
2019 HDC hdc;
2020 HFONT hOldFont;
2021 TEXTMETRICA tm;
2022 RECT rect;
2023 INT height;
2025 LVITEMA item0;
2026 LVITEMA item1;
2027 LVITEMA item2;
2028 static CHAR item0text[] = "item0";
2029 static CHAR item1text[] = "item1";
2030 static CHAR item2text[] = "item2";
2032 hwnd = create_listview_control(LVS_REPORT);
2033 ok(hwnd != NULL, "failed to create a listview window\n");
2035 /* resize in dpiaware manner to fit all 3 items added */
2036 hdc = GetDC(0);
2037 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2038 GetTextMetricsA(hdc, &tm);
2039 /* 2 extra pixels for bounds and header border */
2040 height = tm.tmHeight + 2;
2041 SelectObject(hdc, hOldFont);
2042 ReleaseDC(0, hdc);
2044 GetWindowRect(hwnd, &rect);
2045 /* 3 items + 1 header + 1 to be sure */
2046 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2048 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2050 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2051 expect(0, r);
2053 /* [item0] */
2054 item0.mask = LVIF_TEXT;
2055 item0.iItem = 0;
2056 item0.iSubItem = 0;
2057 item0.pszText = item0text;
2058 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2059 expect(0, r);
2061 /* [item0, item1] */
2062 item1.mask = LVIF_TEXT;
2063 item1.iItem = 1;
2064 item1.iSubItem = 0;
2065 item1.pszText = item1text;
2066 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2067 expect(1, r);
2069 /* [item0, item1, item2] */
2070 item2.mask = LVIF_TEXT;
2071 item2.iItem = 2;
2072 item2.iSubItem = 0;
2073 item2.pszText = item2text;
2074 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2075 expect(2, r);
2077 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2078 expect(3, r);
2080 /* [item0, item1] */
2081 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2082 expect(TRUE, r);
2084 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2085 expect(2, r);
2087 /* [] */
2088 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2089 expect(TRUE, r);
2091 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2092 expect(0, r);
2094 /* [item0] */
2095 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2096 expect(0, r);
2098 /* [item0, item1] */
2099 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2100 expect(1, r);
2102 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2103 expect(2, r);
2105 /* [item0, item1, item2] */
2106 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2107 expect(2, r);
2109 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2110 expect(3, r);
2112 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2114 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2115 DestroyWindow(hwnd);
2118 static void test_item_position(void)
2120 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2122 HWND hwnd;
2123 DWORD r;
2124 POINT position;
2126 LVITEMA item0;
2127 LVITEMA item1;
2128 LVITEMA item2;
2129 static CHAR item0text[] = "item0";
2130 static CHAR item1text[] = "item1";
2131 static CHAR item2text[] = "item2";
2133 hwnd = create_listview_control(LVS_ICON);
2134 ok(hwnd != NULL, "failed to create a listview window\n");
2136 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2138 /* [item0] */
2139 item0.mask = LVIF_TEXT;
2140 item0.iItem = 0;
2141 item0.iSubItem = 0;
2142 item0.pszText = item0text;
2143 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2144 expect(0, r);
2146 /* [item0, item1] */
2147 item1.mask = LVIF_TEXT;
2148 item1.iItem = 1;
2149 item1.iSubItem = 0;
2150 item1.pszText = item1text;
2151 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2152 expect(1, r);
2154 /* [item0, item1, item2] */
2155 item2.mask = LVIF_TEXT;
2156 item2.iItem = 2;
2157 item2.iSubItem = 0;
2158 item2.pszText = item2text;
2159 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2160 expect(2, r);
2162 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2163 expect(TRUE, r);
2164 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2165 expect(TRUE, r);
2166 expect2(10, 5, position.x, position.y);
2168 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2169 expect(TRUE, r);
2170 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2171 expect(TRUE, r);
2172 expect2(0, 0, position.x, position.y);
2174 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2175 expect(TRUE, r);
2176 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2177 expect(TRUE, r);
2178 expect2(20, 20, position.x, position.y);
2180 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2182 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2183 DestroyWindow(hwnd);
2186 static void test_getorigin(void)
2188 /* LVM_GETORIGIN */
2190 HWND hwnd;
2191 DWORD r;
2192 POINT position;
2194 position.x = position.y = 0;
2196 hwnd = create_listview_control(LVS_ICON);
2197 ok(hwnd != NULL, "failed to create a listview window\n");
2198 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2200 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2201 expect(TRUE, r);
2202 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2203 DestroyWindow(hwnd);
2205 hwnd = create_listview_control(LVS_SMALLICON);
2206 ok(hwnd != NULL, "failed to create a listview window\n");
2207 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2209 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2210 expect(TRUE, r);
2211 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2212 DestroyWindow(hwnd);
2214 hwnd = create_listview_control(LVS_LIST);
2215 ok(hwnd != NULL, "failed to create a listview window\n");
2216 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2218 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2219 expect(FALSE, r);
2220 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2221 DestroyWindow(hwnd);
2223 hwnd = create_listview_control(LVS_REPORT);
2224 ok(hwnd != NULL, "failed to create a listview window\n");
2225 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2227 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2228 expect(FALSE, r);
2229 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2230 DestroyWindow(hwnd);
2233 static void test_multiselect(void)
2235 typedef struct t_select_task
2237 const char *descr;
2238 int initPos;
2239 int loopVK;
2240 int count;
2241 int result;
2242 } select_task;
2244 HWND hwnd;
2245 INT r;
2246 int i, j;
2247 static const int items=5;
2248 DWORD item_count;
2249 BYTE kstate[256];
2250 select_task task;
2251 LONG_PTR style;
2252 LVITEMA item;
2254 static struct t_select_task task_list[] = {
2255 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2256 { "using VK_UP", -1, VK_UP, -1, -1 },
2257 { "using VK_END", 0, VK_END, 1, -1 },
2258 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2261 hwnd = create_listview_control(LVS_REPORT);
2263 for (i = 0; i < items; i++)
2264 insert_item(hwnd, 0);
2266 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2267 expect(items, item_count);
2269 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2270 ok(r == -1, "got %d\n", r);
2272 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2273 ok(r == -1, "got %d\n", r);
2275 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2276 ok(r == 0, "got %d\n", r);
2278 /* out of range index */
2279 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, items);
2280 ok(r == 0, "got %d\n", r);
2282 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2283 ok(r == 0, "got %d\n", r);
2285 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -2);
2286 ok(r == 0, "got %d\n", r);
2288 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2289 ok(r == 0, "got %d\n", r);
2291 for (i = 0; i < sizeof(task_list)/sizeof(task_list[0]); i++) {
2292 DWORD selected_count;
2293 LVITEMA item;
2295 task = task_list[i];
2297 /* deselect all items */
2298 item.state = 0;
2299 item.stateMask = LVIS_SELECTED;
2300 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2301 ok(r, "got %d\n", r);
2302 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2304 /* set initial position */
2305 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2306 ok(r, "got %d\n", r);
2308 item.state = LVIS_SELECTED;
2309 item.stateMask = LVIS_SELECTED;
2310 r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2311 ok(r, "got %d\n", r);
2313 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2314 ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2316 /* Set SHIFT key pressed */
2317 GetKeyboardState(kstate);
2318 kstate[VK_SHIFT]=0x80;
2319 SetKeyboardState(kstate);
2321 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2322 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2323 expect(0,r);
2324 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2325 expect(0,r);
2328 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2330 ok((task.result == -1 ? item_count : task.result) == selected_count,
2331 "Failed multiple selection %s. There should be %d selected items (is %d)\n",
2332 task.descr, item_count, selected_count);
2334 /* Set SHIFT key released */
2335 GetKeyboardState(kstate);
2336 kstate[VK_SHIFT]=0x00;
2337 SetKeyboardState(kstate);
2339 DestroyWindow(hwnd);
2341 /* make multiple selection, then switch to LVS_SINGLESEL */
2342 hwnd = create_listview_control(LVS_REPORT);
2343 for (i=0;i<items;i++) {
2344 insert_item(hwnd, 0);
2346 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2347 expect(items,item_count);
2349 /* try with NULL pointer */
2350 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2351 expect(FALSE, r);
2353 /* select all, check notifications */
2354 item.state = 0;
2355 item.stateMask = LVIS_SELECTED;
2356 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2357 ok(r, "got %d\n", r);
2359 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2361 item.stateMask = LVIS_SELECTED;
2362 item.state = LVIS_SELECTED;
2363 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2364 expect(TRUE, r);
2366 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2367 "select all notification", FALSE);
2369 /* select all again (all selected already) */
2370 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2372 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2374 item.stateMask = LVIS_SELECTED;
2375 item.state = LVIS_SELECTED;
2376 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2377 expect(TRUE, r);
2379 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2380 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2381 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2383 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2384 "select all notification 2", FALSE);
2386 /* deselect all items */
2387 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2389 item.state = 0;
2390 item.stateMask = LVIS_SELECTED;
2391 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2392 ok(r, "got %d\n", r);
2394 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2395 "deselect all notification", FALSE);
2397 /* deselect all items again */
2398 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2399 item.state = 0;
2400 item.stateMask = LVIS_SELECTED;
2401 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2402 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2404 /* any non-zero state value does the same */
2405 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2407 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2409 item.stateMask = LVIS_SELECTED;
2410 item.state = LVIS_CUT;
2411 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2412 expect(TRUE, r);
2414 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2415 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2416 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2418 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2419 "set state all notification 3", FALSE);
2421 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2422 ok(r, "got %d\n", r);
2423 for (i = 0; i < 3; i++) {
2424 item.state = LVIS_SELECTED;
2425 item.stateMask = LVIS_SELECTED;
2426 r = SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2427 ok(r, "got %d\n", r);
2430 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2431 expect(3, r);
2432 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2433 expect(-1, r);
2435 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2436 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2437 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2438 /* check that style is accepted */
2439 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2440 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2442 for (i=0;i<3;i++) {
2443 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2444 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2446 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2447 expect(3, r);
2448 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2449 ok(r == -1, "got %d\n", r);
2451 /* select one more */
2452 item.state = LVIS_SELECTED;
2453 item.stateMask = LVIS_SELECTED;
2454 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2455 ok(r, "got %d\n", r);
2457 for (i=0;i<3;i++) {
2458 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2459 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2462 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2463 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2465 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2466 expect(1, r);
2467 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2468 expect(-1, r);
2470 /* try to select all on LVS_SINGLESEL */
2471 memset(&item, 0, sizeof(item));
2472 item.stateMask = LVIS_SELECTED;
2473 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2474 expect(TRUE, r);
2475 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2476 ok(r == -1, "got %d\n", r);
2478 item.stateMask = LVIS_SELECTED;
2479 item.state = LVIS_SELECTED;
2480 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2481 expect(FALSE, r);
2483 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2484 expect(0, r);
2485 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2486 expect(-1, r);
2488 /* try to deselect all on LVS_SINGLESEL */
2489 item.stateMask = LVIS_SELECTED;
2490 item.state = LVIS_SELECTED;
2491 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2492 expect(TRUE, r);
2494 item.stateMask = LVIS_SELECTED;
2495 item.state = 0;
2496 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2497 expect(TRUE, r);
2498 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2499 expect(0, r);
2501 /* 1. selection mark is update when new focused item is set */
2502 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2503 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2505 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2506 expect(-1, r);
2508 item.stateMask = LVIS_FOCUSED;
2509 item.state = LVIS_FOCUSED;
2510 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2511 expect(TRUE, r);
2513 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2514 expect(0, r);
2516 /* it's not updated if already set */
2517 item.stateMask = LVIS_FOCUSED;
2518 item.state = LVIS_FOCUSED;
2519 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2520 expect(TRUE, r);
2522 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2523 expect(0, r);
2525 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2526 expect(0, r);
2528 item.stateMask = LVIS_FOCUSED;
2529 item.state = LVIS_FOCUSED;
2530 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2531 expect(TRUE, r);
2533 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2534 expect(-1, r);
2536 /* need to reset focused item first */
2537 item.stateMask = LVIS_FOCUSED;
2538 item.state = 0;
2539 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2540 expect(TRUE, r);
2542 item.stateMask = LVIS_FOCUSED;
2543 item.state = LVIS_FOCUSED;
2544 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2545 expect(TRUE, r);
2547 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2548 expect(2, r);
2550 item.stateMask = LVIS_FOCUSED;
2551 item.state = 0;
2552 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2553 expect(TRUE, r);
2555 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2556 expect(2, r);
2558 /* 2. same tests, with LVM_SETITEM */
2559 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2560 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2562 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2563 expect(2, r);
2565 item.stateMask = LVIS_FOCUSED;
2566 item.state = LVIS_FOCUSED;
2567 item.mask = LVIF_STATE;
2568 item.iItem = item.iSubItem = 0;
2569 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2570 expect(TRUE, r);
2572 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2573 expect(0, r);
2575 /* it's not updated if already set */
2576 item.stateMask = LVIS_FOCUSED;
2577 item.state = LVIS_FOCUSED;
2578 item.mask = LVIF_STATE;
2579 item.iItem = 1;
2580 item.iSubItem = 0;
2581 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2582 expect(TRUE, r);
2584 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2585 expect(0, r);
2587 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2588 expect(0, r);
2590 item.stateMask = LVIS_FOCUSED;
2591 item.state = LVIS_FOCUSED;
2592 item.mask = LVIF_STATE;
2593 item.iItem = 1;
2594 item.iSubItem = 0;
2595 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2596 expect(TRUE, r);
2598 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2599 expect(-1, r);
2601 /* need to reset focused item first */
2602 item.stateMask = LVIS_FOCUSED;
2603 item.state = 0;
2604 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2605 expect(TRUE, r);
2607 item.stateMask = LVIS_FOCUSED;
2608 item.state = LVIS_FOCUSED;
2609 item.mask = LVIF_STATE;
2610 item.iItem = 2;
2611 item.iSubItem = 0;
2612 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2613 expect(TRUE, r);
2615 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2616 expect(2, r);
2618 item.stateMask = LVIS_FOCUSED;
2619 item.state = 0;
2620 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2621 expect(TRUE, r);
2623 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2624 expect(2, r);
2626 DestroyWindow(hwnd);
2629 static void test_subitem_rect(void)
2631 HWND hwnd;
2632 DWORD r;
2633 LVCOLUMNA col;
2634 RECT rect, rect2;
2635 INT arr[3];
2637 /* test LVM_GETSUBITEMRECT for header */
2638 hwnd = create_listview_control(LVS_REPORT);
2639 ok(hwnd != NULL, "failed to create a listview window\n");
2640 /* add some columns */
2641 memset(&col, 0, sizeof(LVCOLUMNA));
2642 col.mask = LVCF_WIDTH;
2643 col.cx = 100;
2644 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2645 expect(0, r);
2646 col.cx = 150;
2647 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2648 expect(1, r);
2649 col.cx = 200;
2650 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2651 expect(2, r);
2652 /* item = -1 means header, subitem index is 1 based */
2653 SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2654 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2655 expect(0, r);
2657 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2658 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2659 expect(1, r);
2661 expect(100, rect.left);
2662 expect(250, rect.right);
2663 expect(3, rect.top);
2665 SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2666 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2667 expect(1, r);
2669 expect(250, rect.left);
2670 expect(450, rect.right);
2671 expect(3, rect.top);
2673 /* item LVS_REPORT padding isn't applied to subitems */
2674 insert_item(hwnd, 0);
2676 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2677 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2678 expect(1, r);
2679 expect(100, rect.left);
2680 expect(250, rect.right);
2682 SetRect(&rect, LVIR_ICON, 1, 0, 0);
2683 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2684 expect(1, r);
2685 /* no icon attached - zero width rectangle, with no left padding */
2686 expect(100, rect.left);
2687 expect(100, rect.right);
2689 SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2690 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2691 expect(1, r);
2692 /* same as full LVIR_BOUNDS */
2693 expect(100, rect.left);
2694 expect(250, rect.right);
2696 r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2697 ok(r, "got %d\n", r);
2699 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2700 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2701 expect(1, r);
2702 expect(90, rect.left);
2703 expect(240, rect.right);
2705 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2707 /* test header interaction */
2708 subclass_header(hwnd);
2709 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2711 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2712 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2713 expect(1, r);
2715 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2716 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2717 expect(1, r);
2719 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2720 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2721 expect(1, r);
2723 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2724 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2725 expect(1, r);
2727 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2729 DestroyWindow(hwnd);
2731 /* test subitem rects after re-arranging columns */
2732 hwnd = create_listview_control(LVS_REPORT);
2733 ok(hwnd != NULL, "failed to create a listview window\n");
2734 memset(&col, 0, sizeof(LVCOLUMNA));
2735 col.mask = LVCF_WIDTH;
2737 col.cx = 100;
2738 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2739 expect(0, r);
2741 col.cx = 200;
2742 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2743 expect(1, r);
2745 col.cx = 300;
2746 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2747 expect(2, r);
2749 insert_item(hwnd, 0);
2750 insert_item(hwnd, 1);
2752 /* wrong item is refused for main item */
2753 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2754 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2755 expect(FALSE, r);
2757 /* for subitems rectangle is calculated even if there's no item added */
2758 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2759 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2760 expect(TRUE, r);
2762 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2763 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2764 expect(TRUE, r);
2765 expect(rect.right, rect2.right);
2766 expect(rect.left, rect2.left);
2767 expect(rect.bottom, rect2.top);
2768 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2770 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2771 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2772 expect(TRUE, r);
2774 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2775 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2776 expect(TRUE, r);
2777 expect(0, rect.left);
2778 expect(600, rect.right);
2780 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2781 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2782 expect(TRUE, r);
2783 expect(0, rect.left);
2784 expect(200, rect.right);
2786 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2787 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2788 expect(TRUE, r);
2789 expect(0, rect2.left);
2790 expect(200, rect2.right);
2791 /* items are of the same height */
2792 ok(rect2.top > 0, "expected positive item height\n");
2793 expect(rect.bottom, rect2.top);
2794 expect(rect.bottom * 2 - rect.top, rect2.bottom);
2796 SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
2797 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2798 expect(TRUE, r);
2799 expect(300, rect.left);
2800 expect(600, rect.right);
2802 DestroyWindow(hwnd);
2804 /* try it for non LVS_REPORT style */
2805 hwnd = CreateWindowA("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2806 GetModuleHandleA(NULL), 0);
2807 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
2808 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2809 expect(0, r);
2810 /* rect is unchanged */
2811 expect(0, rect.left);
2812 expect(-10, rect.right);
2813 expect(1, rect.top);
2814 expect(-10, rect.bottom);
2815 DestroyWindow(hwnd);
2818 /* comparison callback for test_sorting */
2819 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2821 if (first == second) return 0;
2822 return (first > second ? 1 : -1);
2825 static void test_sorting(void)
2827 HWND hwnd;
2828 LVITEMA item = {0};
2829 INT r;
2830 LONG_PTR style;
2831 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2832 CHAR buff[10];
2834 hwnd = create_listview_control(LVS_REPORT);
2835 ok(hwnd != NULL, "failed to create a listview window\n");
2837 /* insert some items */
2838 item.mask = LVIF_PARAM | LVIF_STATE;
2839 item.state = LVIS_SELECTED;
2840 item.iItem = 0;
2841 item.iSubItem = 0;
2842 item.lParam = 3;
2843 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2844 expect(0, r);
2846 item.mask = LVIF_PARAM;
2847 item.iItem = 1;
2848 item.iSubItem = 0;
2849 item.lParam = 2;
2850 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2851 expect(1, r);
2853 item.mask = LVIF_STATE | LVIF_PARAM;
2854 item.state = LVIS_SELECTED;
2855 item.iItem = 2;
2856 item.iSubItem = 0;
2857 item.lParam = 4;
2858 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2859 expect(2, r);
2861 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2862 expect(-1, r);
2864 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2865 expect(2, r);
2867 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2868 expect(TRUE, r);
2870 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2871 expect(2, r);
2872 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2873 expect(-1, r);
2874 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2875 expect(0, r);
2876 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2877 expect(LVIS_SELECTED, r);
2878 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2879 expect(LVIS_SELECTED, r);
2881 DestroyWindow(hwnd);
2883 /* switch to LVS_SORTASCENDING when some items added */
2884 hwnd = create_listview_control(LVS_REPORT);
2885 ok(hwnd != NULL, "failed to create a listview window\n");
2887 item.mask = LVIF_TEXT;
2888 item.iItem = 0;
2889 item.iSubItem = 0;
2890 item.pszText = names[1];
2891 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2892 expect(0, r);
2894 item.mask = LVIF_TEXT;
2895 item.iItem = 1;
2896 item.iSubItem = 0;
2897 item.pszText = names[2];
2898 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2899 expect(1, r);
2901 item.mask = LVIF_TEXT;
2902 item.iItem = 2;
2903 item.iSubItem = 0;
2904 item.pszText = names[0];
2905 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2906 expect(2, r);
2908 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2909 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2910 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2911 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2913 /* no sorting performed when switched to LVS_SORTASCENDING */
2914 item.mask = LVIF_TEXT;
2915 item.iItem = 0;
2916 item.pszText = buff;
2917 item.cchTextMax = sizeof(buff);
2918 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2919 expect(TRUE, r);
2920 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2922 item.iItem = 1;
2923 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2924 expect(TRUE, r);
2925 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2927 item.iItem = 2;
2928 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2929 expect(TRUE, r);
2930 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2932 /* adding new item doesn't resort list */
2933 item.mask = LVIF_TEXT;
2934 item.iItem = 3;
2935 item.iSubItem = 0;
2936 item.pszText = names[3];
2937 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2938 expect(3, r);
2940 item.mask = LVIF_TEXT;
2941 item.iItem = 0;
2942 item.pszText = buff;
2943 item.cchTextMax = sizeof(buff);
2944 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2945 expect(TRUE, r);
2946 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2948 item.iItem = 1;
2949 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2950 expect(TRUE, r);
2951 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2953 item.iItem = 2;
2954 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2955 expect(TRUE, r);
2956 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2958 item.iItem = 3;
2959 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2960 expect(TRUE, r);
2961 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2963 /* corner case - item should be placed at first position */
2964 item.mask = LVIF_TEXT;
2965 item.iItem = 4;
2966 item.iSubItem = 0;
2967 item.pszText = names[4];
2968 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2969 expect(0, r);
2971 item.iItem = 0;
2972 item.pszText = buff;
2973 item.cchTextMax = sizeof(buff);
2974 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2975 expect(TRUE, r);
2976 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2978 item.iItem = 1;
2979 item.pszText = buff;
2980 item.cchTextMax = sizeof(buff);
2981 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2982 expect(TRUE, r);
2983 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2985 item.iItem = 2;
2986 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2987 expect(TRUE, r);
2988 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2990 item.iItem = 3;
2991 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2992 expect(TRUE, r);
2993 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2995 item.iItem = 4;
2996 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2997 expect(TRUE, r);
2998 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3000 DestroyWindow(hwnd);
3003 static void test_ownerdata(void)
3005 static char test_str[] = "test";
3007 HWND hwnd;
3008 LONG_PTR style, ret;
3009 DWORD res;
3010 LVITEMA item;
3012 /* it isn't possible to set LVS_OWNERDATA after creation */
3013 if (g_is_below_5)
3015 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3017 else
3019 hwnd = create_listview_control(LVS_REPORT);
3020 ok(hwnd != NULL, "failed to create a listview window\n");
3021 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3022 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3024 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3026 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3027 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3028 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3029 "try to switch to LVS_OWNERDATA seq", FALSE);
3031 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3032 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3033 DestroyWindow(hwnd);
3036 /* try to set LVS_OWNERDATA after creation just having it */
3037 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3038 ok(hwnd != NULL, "failed to create a listview window\n");
3039 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3040 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3042 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3044 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3045 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3046 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3047 "try to switch to LVS_OWNERDATA seq", FALSE);
3048 DestroyWindow(hwnd);
3050 /* try to remove LVS_OWNERDATA after creation just having it */
3051 if (g_is_below_5)
3053 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3055 else
3057 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3058 ok(hwnd != NULL, "failed to create a listview window\n");
3059 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3060 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3062 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3064 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3065 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3066 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3067 "try to switch to LVS_OWNERDATA seq", FALSE);
3068 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3069 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3070 DestroyWindow(hwnd);
3073 /* try select an item */
3074 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3075 ok(hwnd != NULL, "failed to create a listview window\n");
3076 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3077 expect(1, res);
3078 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3079 expect(0, res);
3080 memset(&item, 0, sizeof(item));
3081 item.stateMask = LVIS_SELECTED;
3082 item.state = LVIS_SELECTED;
3083 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3084 expect(TRUE, res);
3085 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3086 expect(1, res);
3087 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3088 expect(1, res);
3089 DestroyWindow(hwnd);
3091 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3092 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3093 ok(hwnd != NULL, "failed to create a listview window\n");
3094 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3095 expect(1, res);
3096 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3097 expect(1, res);
3098 memset(&item, 0, sizeof(item));
3099 item.mask = LVIF_STATE;
3100 item.iItem = 0;
3101 item.stateMask = LVIS_SELECTED;
3102 item.state = LVIS_SELECTED;
3103 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3104 expect(FALSE, res);
3105 memset(&item, 0, sizeof(item));
3106 item.pszText = test_str;
3107 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3108 expect(FALSE, res);
3109 DestroyWindow(hwnd);
3111 /* check notifications after focused/selected changed */
3112 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3113 ok(hwnd != NULL, "failed to create a listview window\n");
3114 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3115 expect(1, res);
3117 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3119 memset(&item, 0, sizeof(item));
3120 item.stateMask = LVIS_SELECTED;
3121 item.state = LVIS_SELECTED;
3122 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3123 expect(TRUE, res);
3125 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3126 "ownerdata select notification", TRUE);
3128 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3130 memset(&item, 0, sizeof(item));
3131 item.stateMask = LVIS_FOCUSED;
3132 item.state = LVIS_FOCUSED;
3133 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3134 expect(TRUE, res);
3136 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3137 "ownerdata focus notification", TRUE);
3139 /* select all, check notifications */
3140 item.stateMask = LVIS_SELECTED;
3141 item.state = 0;
3142 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3143 expect(TRUE, res);
3145 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3147 item.stateMask = LVIS_SELECTED;
3148 item.state = LVIS_SELECTED;
3150 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3151 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3152 expect(TRUE, res);
3153 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3154 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3155 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3156 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3157 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3158 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3159 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3161 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3162 "ownerdata select all notification", FALSE);
3164 /* select all again, note that all items are selected already */
3165 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3166 item.stateMask = LVIS_SELECTED;
3167 item.state = LVIS_SELECTED;
3169 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3170 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3171 expect(TRUE, res);
3172 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3173 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3174 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3175 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3176 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3177 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3178 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3180 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3181 "ownerdata select all notification", FALSE);
3183 /* deselect all */
3184 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3185 item.stateMask = LVIS_SELECTED;
3186 item.state = 0;
3188 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3189 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3190 expect(TRUE, res);
3191 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3192 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3193 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3194 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3195 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3196 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3197 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3199 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3200 "ownerdata deselect all notification", TRUE);
3202 /* nothing selected, deselect all again */
3203 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3204 item.stateMask = LVIS_SELECTED;
3205 item.state = 0;
3207 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3208 expect(TRUE, res);
3210 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3212 /* select one, then deselect all */
3213 item.stateMask = LVIS_SELECTED;
3214 item.state = LVIS_SELECTED;
3215 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3216 expect(TRUE, res);
3217 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3218 item.stateMask = LVIS_SELECTED;
3219 item.state = 0;
3221 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3222 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3223 expect(TRUE, res);
3224 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3225 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3226 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3227 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3228 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3229 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3230 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3232 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3233 "ownerdata select all notification", TRUE);
3235 /* remove focused, try to focus all */
3236 item.stateMask = LVIS_FOCUSED;
3237 item.state = LVIS_FOCUSED;
3238 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3239 expect(TRUE, res);
3240 item.stateMask = LVIS_FOCUSED;
3241 item.state = 0;
3242 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3243 expect(TRUE, res);
3244 item.stateMask = LVIS_FOCUSED;
3245 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3246 expect(0, res);
3248 /* setting all to focused returns failure value */
3249 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3250 item.stateMask = LVIS_FOCUSED;
3251 item.state = LVIS_FOCUSED;
3253 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3254 expect(FALSE, res);
3256 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3257 "ownerdata focus all notification", FALSE);
3259 /* focus single item, remove all */
3260 item.stateMask = LVIS_FOCUSED;
3261 item.state = LVIS_FOCUSED;
3262 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3263 expect(TRUE, res);
3264 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3265 item.stateMask = LVIS_FOCUSED;
3266 item.state = 0;
3268 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3269 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3270 expect(TRUE, res);
3271 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3272 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3273 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3274 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3275 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3276 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3277 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3279 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3280 "ownerdata remove focus all notification", TRUE);
3282 /* set all cut */
3283 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3284 item.stateMask = LVIS_CUT;
3285 item.state = LVIS_CUT;
3287 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3288 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3289 expect(TRUE, res);
3290 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3291 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3292 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3293 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3294 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3295 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3296 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3298 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3299 "ownerdata cut all notification", FALSE);
3301 /* all marked cut, try again */
3302 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3303 item.stateMask = LVIS_CUT;
3304 item.state = LVIS_CUT;
3306 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3307 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3308 expect(TRUE, res);
3309 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3310 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3311 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3312 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3313 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3314 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3315 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3317 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3318 "ownerdata cut all notification #2", FALSE);
3320 DestroyWindow(hwnd);
3322 /* check notifications on LVM_GETITEM */
3323 /* zero callback mask */
3324 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3325 ok(hwnd != NULL, "failed to create a listview window\n");
3326 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3327 expect(1, res);
3329 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3331 memset(&item, 0, sizeof(item));
3332 item.stateMask = LVIS_SELECTED;
3333 item.mask = LVIF_STATE;
3334 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3335 expect(TRUE, res);
3337 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3338 "ownerdata getitem selected state 1", FALSE);
3340 /* non zero callback mask but not we asking for */
3341 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3342 expect(TRUE, res);
3344 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3346 memset(&item, 0, sizeof(item));
3347 item.stateMask = LVIS_SELECTED;
3348 item.mask = LVIF_STATE;
3349 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3350 expect(TRUE, res);
3352 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3353 "ownerdata getitem selected state 2", FALSE);
3355 /* LVIS_OVERLAYMASK callback mask, asking for index */
3356 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3358 memset(&item, 0, sizeof(item));
3359 item.stateMask = LVIS_OVERLAYMASK;
3360 item.mask = LVIF_STATE;
3361 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3362 expect(TRUE, res);
3364 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3365 "ownerdata getitem selected state 2", FALSE);
3367 DestroyWindow(hwnd);
3369 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3370 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3371 ok(hwnd != NULL, "failed to create a listview window\n");
3372 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3373 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3374 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3375 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3376 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3377 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3378 DestroyWindow(hwnd);
3379 /* apparently it's allowed to switch these style on after creation */
3380 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3381 ok(hwnd != NULL, "failed to create a listview window\n");
3382 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3383 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3384 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3385 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3386 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3387 DestroyWindow(hwnd);
3389 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3390 ok(hwnd != NULL, "failed to create a listview window\n");
3391 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3392 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3393 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3394 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3395 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3396 DestroyWindow(hwnd);
3398 /* The focused item is updated after the invalidation */
3399 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3400 ok(hwnd != NULL, "failed to create a listview window\n");
3401 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3402 expect(TRUE, res);
3404 memset(&item, 0, sizeof(item));
3405 item.stateMask = LVIS_FOCUSED;
3406 item.state = LVIS_FOCUSED;
3407 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3408 expect(TRUE, res);
3410 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3411 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3412 expect(TRUE, res);
3413 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3414 "ownerdata setitemcount", FALSE);
3416 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3417 expect(-1, res);
3418 DestroyWindow(hwnd);
3421 static void test_norecompute(void)
3423 static CHAR testA[] = "test";
3424 CHAR buff[10];
3425 LVITEMA item;
3426 HWND hwnd;
3427 DWORD res;
3429 /* self containing control */
3430 hwnd = create_listview_control(LVS_REPORT);
3431 ok(hwnd != NULL, "failed to create a listview window\n");
3432 memset(&item, 0, sizeof(item));
3433 item.mask = LVIF_TEXT | LVIF_STATE;
3434 item.iItem = 0;
3435 item.stateMask = LVIS_SELECTED;
3436 item.state = LVIS_SELECTED;
3437 item.pszText = testA;
3438 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3439 expect(0, res);
3440 /* retrieve with LVIF_NORECOMPUTE */
3441 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3442 item.iItem = 0;
3443 item.pszText = buff;
3444 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3445 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3446 expect(TRUE, res);
3447 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3449 item.mask = LVIF_TEXT;
3450 item.iItem = 1;
3451 item.pszText = LPSTR_TEXTCALLBACKA;
3452 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3453 expect(1, res);
3455 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3456 item.iItem = 1;
3457 item.pszText = buff;
3458 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3460 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3461 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3462 expect(TRUE, res);
3463 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3464 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3465 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3467 DestroyWindow(hwnd);
3469 /* LVS_OWNERDATA */
3470 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3471 ok(hwnd != NULL, "failed to create a listview window\n");
3473 item.mask = LVIF_STATE;
3474 item.stateMask = LVIS_SELECTED;
3475 item.state = LVIS_SELECTED;
3476 item.iItem = 0;
3477 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3478 expect(0, res);
3480 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3481 item.iItem = 0;
3482 item.pszText = buff;
3483 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3484 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3485 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3486 expect(TRUE, res);
3487 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3488 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3489 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3491 DestroyWindow(hwnd);
3494 static void test_nosortheader(void)
3496 HWND hwnd, header;
3497 LONG_PTR style;
3499 hwnd = create_listview_control(LVS_REPORT);
3500 ok(hwnd != NULL, "failed to create a listview window\n");
3502 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3503 ok(IsWindow(header), "header expected\n");
3505 style = GetWindowLongPtrA(header, GWL_STYLE);
3506 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3508 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3509 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3510 /* HDS_BUTTONS retained */
3511 style = GetWindowLongPtrA(header, GWL_STYLE);
3512 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3514 DestroyWindow(hwnd);
3516 /* create with LVS_NOSORTHEADER */
3517 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3518 ok(hwnd != NULL, "failed to create a listview window\n");
3520 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3521 ok(IsWindow(header), "header expected\n");
3523 style = GetWindowLongPtrA(header, GWL_STYLE);
3524 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3526 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3527 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3528 /* not changed here */
3529 style = GetWindowLongPtrA(header, GWL_STYLE);
3530 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3532 DestroyWindow(hwnd);
3535 static void test_setredraw(void)
3537 HWND hwnd;
3538 DWORD_PTR style;
3539 DWORD ret;
3540 HDC hdc;
3541 RECT rect;
3543 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3544 ok(hwnd != NULL, "failed to create a listview window\n");
3546 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3547 ListView seems to handle it internally without DefWinProc */
3549 /* default value first */
3550 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3551 expect(0, ret);
3552 /* disable */
3553 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3554 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3555 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3556 expect(0, ret);
3557 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3558 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3559 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3560 expect(0, ret);
3562 /* check update rect after redrawing */
3563 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3564 expect(0, ret);
3565 InvalidateRect(hwnd, NULL, FALSE);
3566 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3567 rect.right = rect.bottom = 1;
3568 GetUpdateRect(hwnd, &rect, FALSE);
3569 expect(0, rect.right);
3570 expect(0, rect.bottom);
3572 /* WM_ERASEBKGND */
3573 hdc = GetWindowDC(hwndparent);
3574 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3575 expect(TRUE, ret);
3576 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3577 expect(0, ret);
3578 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3579 expect(TRUE, ret);
3580 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3581 expect(0, ret);
3582 ReleaseDC(hwndparent, hdc);
3584 /* check notification messages to show that repainting is disabled */
3585 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3586 expect(TRUE, ret);
3587 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3588 expect(0, ret);
3589 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3591 InvalidateRect(hwnd, NULL, TRUE);
3592 UpdateWindow(hwnd);
3593 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3594 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3596 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3597 expect(TRUE, ret);
3598 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3599 InvalidateRect(hwnd, NULL, TRUE);
3600 UpdateWindow(hwnd);
3601 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3602 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3604 /* message isn't forwarded to header */
3605 subclass_header(hwnd);
3606 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3607 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3608 expect(0, ret);
3609 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3610 "WM_SETREDRAW: not forwarded to header", FALSE);
3612 DestroyWindow(hwnd);
3615 static void test_hittest(void)
3617 HWND hwnd;
3618 DWORD r;
3619 RECT bounds;
3620 LVITEMA item;
3621 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3622 POINT pos;
3623 INT x, y, i;
3624 WORD vert;
3625 HIMAGELIST himl, himl2;
3626 HBITMAP hbmp;
3628 hwnd = create_listview_control(LVS_REPORT);
3629 ok(hwnd != NULL, "failed to create a listview window\n");
3631 /* LVS_REPORT with a single subitem (2 columns) */
3632 insert_column(hwnd, 0);
3633 insert_column(hwnd, 1);
3634 insert_item(hwnd, 0);
3636 item.iSubItem = 0;
3637 /* the only purpose of that line is to be as long as a half item rect */
3638 item.pszText = text;
3639 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3640 expect(TRUE, r);
3642 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3643 expect(TRUE, r);
3644 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3645 expect(TRUE, r);
3647 SetRect(&bounds, LVIR_BOUNDS, 0, 0, 0);
3648 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3649 expect(1, r);
3650 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3651 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3652 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3653 vert = HIWORD(r);
3654 ok(bounds.bottom - bounds.top == vert,
3655 "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3656 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3657 expect(TRUE, r);
3659 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3661 /* outside columns by x position - valid is [0, 199] */
3662 x = -1;
3663 y = pos.y + (bounds.bottom - bounds.top) / 2;
3664 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3665 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3667 x = pos.x + 50; /* column half width */
3668 y = pos.y + (bounds.bottom - bounds.top) / 2;
3669 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3670 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3671 x = pos.x + 150; /* outside column */
3672 y = pos.y + (bounds.bottom - bounds.top) / 2;
3673 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3674 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3675 y = (bounds.bottom - bounds.top) / 2;
3676 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3677 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3678 /* outside possible client rectangle (to right) */
3679 x = pos.x + 500;
3680 y = pos.y + (bounds.bottom - bounds.top) / 2;
3681 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3682 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3683 y = (bounds.bottom - bounds.top) / 2;
3684 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3685 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3686 /* subitem returned with -1 item too */
3687 x = pos.x + 150;
3688 y = bounds.top - vert;
3689 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3690 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3691 /* return values appear to underflow with negative indices */
3692 i = -2;
3693 y = y - vert;
3694 while (i > -10) {
3695 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3696 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3697 y = y - vert;
3698 i--;
3700 /* parent client area is 100x100 by default */
3701 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3702 x = pos.x + 150; /* outside column */
3703 y = pos.y + (bounds.bottom - bounds.top) / 2;
3704 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3705 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3706 y = (bounds.bottom - bounds.top) / 2;
3707 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3708 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3709 /* the same with LVS_EX_FULLROWSELECT */
3710 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3711 x = pos.x + 150; /* outside column */
3712 y = pos.y + (bounds.bottom - bounds.top) / 2;
3713 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3714 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3715 y = (bounds.bottom - bounds.top) / 2;
3716 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3717 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3718 x = pos.x + 150; /* outside column */
3719 y = pos.y + (bounds.bottom - bounds.top) / 2;
3720 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3721 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3722 y = (bounds.bottom - bounds.top) / 2;
3723 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3724 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3725 /* outside possible client rectangle (to right) */
3726 x = pos.x + 500;
3727 y = pos.y + (bounds.bottom - bounds.top) / 2;
3728 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3729 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3730 y = (bounds.bottom - bounds.top) / 2;
3731 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3732 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3733 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3734 himl = ImageList_Create(16, 16, 0, 4, 4);
3735 ok(himl != NULL, "failed to create imagelist\n");
3736 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3737 ok(hbmp != NULL, "failed to create bitmap\n");
3738 r = ImageList_Add(himl, hbmp, 0);
3739 ok(r == 0, "should be zero\n");
3740 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3741 ok(hbmp != NULL, "failed to create bitmap\n");
3742 r = ImageList_Add(himl, hbmp, 0);
3743 ok(r == 1, "should be one\n");
3745 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3746 expect(0, r);
3748 item.mask = LVIF_IMAGE;
3749 item.iImage = 0;
3750 item.iItem = 0;
3751 item.iSubItem = 0;
3752 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3753 expect(TRUE, r);
3754 /* on state icon */
3755 x = pos.x + 8;
3756 y = pos.y + (bounds.bottom - bounds.top) / 2;
3757 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3758 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3759 y = (bounds.bottom - bounds.top) / 2;
3760 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3762 /* state icons indices are 1 based, check with valid index */
3763 item.mask = LVIF_STATE;
3764 item.state = INDEXTOSTATEIMAGEMASK(1);
3765 item.stateMask = LVIS_STATEIMAGEMASK;
3766 item.iItem = 0;
3767 item.iSubItem = 0;
3768 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3769 expect(TRUE, r);
3770 /* on state icon */
3771 x = pos.x + 8;
3772 y = pos.y + (bounds.bottom - bounds.top) / 2;
3773 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3774 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3775 y = (bounds.bottom - bounds.top) / 2;
3776 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3778 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3779 ok(himl2 == himl, "should return handle\n");
3781 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3782 expect(0, r);
3783 /* on item icon */
3784 x = pos.x + 8;
3785 y = pos.y + (bounds.bottom - bounds.top) / 2;
3786 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3787 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3788 y = (bounds.bottom - bounds.top) / 2;
3789 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3791 DestroyWindow(hwnd);
3794 static void test_getviewrect(void)
3796 HWND hwnd;
3797 DWORD r;
3798 RECT rect;
3799 LVITEMA item;
3801 hwnd = create_listview_control(LVS_REPORT);
3802 ok(hwnd != NULL, "failed to create a listview window\n");
3804 /* empty */
3805 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3806 expect(TRUE, r);
3808 insert_column(hwnd, 0);
3809 insert_column(hwnd, 1);
3811 memset(&item, 0, sizeof(item));
3812 item.iItem = 0;
3813 item.iSubItem = 0;
3814 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3815 ok(!r, "got %d\n", r);
3817 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3818 expect(TRUE, r);
3819 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3820 expect(TRUE, r);
3822 SetRect(&rect, -1, -1, -1, -1);
3823 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3824 expect(TRUE, r);
3825 /* left is set to (2e31-1) - XP SP2 */
3826 expect(0, rect.right);
3827 expect(0, rect.top);
3828 expect(0, rect.bottom);
3830 /* switch to LVS_ICON */
3831 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
3833 SetRect(&rect, -1, -1, -1, -1);
3834 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3835 expect(TRUE, r);
3836 expect(0, rect.left);
3837 expect(0, rect.top);
3838 /* precise value differs for 2k, XP and Vista */
3839 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3840 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3842 DestroyWindow(hwnd);
3845 static void test_getitemposition(void)
3847 HWND hwnd, header;
3848 DWORD r;
3849 POINT pt;
3850 RECT rect;
3852 hwnd = create_listview_control(LVS_REPORT);
3853 ok(hwnd != NULL, "failed to create a listview window\n");
3854 header = subclass_header(hwnd);
3856 /* LVS_REPORT, single item, no columns added */
3857 insert_item(hwnd, 0);
3859 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3861 pt.x = pt.y = -1;
3862 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3863 expect(TRUE, r);
3864 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3866 /* LVS_REPORT, single item, single column */
3867 insert_column(hwnd, 0);
3869 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3871 pt.x = pt.y = -1;
3872 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3873 expect(TRUE, r);
3874 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3876 SetRectEmpty(&rect);
3877 r = SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3878 ok(r, "got %d\n", r);
3879 /* some padding? */
3880 expect(2, pt.x);
3881 /* offset by header height */
3882 expect(rect.bottom - rect.top, pt.y);
3884 DestroyWindow(hwnd);
3887 static void test_columnscreation(void)
3889 HWND hwnd, header;
3890 DWORD r;
3892 hwnd = create_listview_control(LVS_REPORT);
3893 ok(hwnd != NULL, "failed to create a listview window\n");
3895 insert_item(hwnd, 0);
3897 /* headers columns aren't created automatically */
3898 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3899 ok(IsWindow(header), "Expected header handle\n");
3900 r = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
3901 expect(0, r);
3903 DestroyWindow(hwnd);
3906 static void test_getitemrect(void)
3908 HWND hwnd;
3909 HIMAGELIST himl, himl_ret;
3910 HBITMAP hbm;
3911 RECT rect;
3912 DWORD r;
3913 LVITEMA item;
3914 LVCOLUMNA col;
3915 INT order[2];
3916 POINT pt;
3918 /* rectangle isn't empty for empty text items */
3919 hwnd = create_listview_control(LVS_LIST);
3920 memset(&item, 0, sizeof(item));
3921 item.mask = 0;
3922 item.iItem = 0;
3923 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3924 expect(0, r);
3925 rect.left = LVIR_LABEL;
3926 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3927 expect(TRUE, r);
3928 expect(0, rect.left);
3929 expect(0, rect.top);
3930 /* estimate it as width / height ratio */
3931 todo_wine
3932 ok((rect.right / rect.bottom) >= 5, "got right %d, bottom %d\n", rect.right, rect.bottom);
3933 DestroyWindow(hwnd);
3935 hwnd = create_listview_control(LVS_REPORT);
3936 ok(hwnd != NULL, "failed to create a listview window\n");
3938 /* empty item */
3939 memset(&item, 0, sizeof(item));
3940 item.iItem = 0;
3941 item.iSubItem = 0;
3942 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3943 expect(0, r);
3945 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3946 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3947 expect(TRUE, r);
3949 /* zero width rectangle with no padding */
3950 expect(0, rect.left);
3951 expect(0, rect.right);
3953 insert_column(hwnd, 0);
3954 insert_column(hwnd, 1);
3956 col.mask = LVCF_WIDTH;
3957 col.cx = 50;
3958 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
3959 expect(TRUE, r);
3961 col.mask = LVCF_WIDTH;
3962 col.cx = 100;
3963 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
3964 expect(TRUE, r);
3966 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3967 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3968 expect(TRUE, r);
3970 /* still no left padding */
3971 expect(0, rect.left);
3972 expect(150, rect.right);
3974 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
3975 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3976 expect(TRUE, r);
3977 /* padding */
3978 expect(2, rect.left);
3980 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
3981 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3982 expect(TRUE, r);
3983 /* padding, column width */
3984 expect(2, rect.left);
3985 expect(50, rect.right);
3987 /* no icons attached */
3988 SetRect(&rect, LVIR_ICON, -1, -1, -1);
3989 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3990 expect(TRUE, r);
3991 /* padding */
3992 expect(2, rect.left);
3993 expect(2, rect.right);
3995 /* change order */
3996 order[0] = 1; order[1] = 0;
3997 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3998 expect(TRUE, r);
3999 pt.x = -1;
4000 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4001 expect(TRUE, r);
4002 /* 1 indexed column width + padding */
4003 expect(102, pt.x);
4004 /* rect is at zero too */
4005 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4006 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4007 expect(TRUE, r);
4008 expect(0, rect.left);
4009 /* just width sum */
4010 expect(150, rect.right);
4012 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4013 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4014 expect(TRUE, r);
4015 /* column width + padding */
4016 expect(102, rect.left);
4018 /* back to initial order */
4019 order[0] = 0; order[1] = 1;
4020 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4021 expect(TRUE, r);
4023 /* state icons */
4024 himl = ImageList_Create(16, 16, 0, 2, 2);
4025 ok(himl != NULL, "failed to create imagelist\n");
4026 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4027 ok(hbm != NULL, "failed to create bitmap\n");
4028 r = ImageList_Add(himl, hbm, 0);
4029 expect(0, r);
4030 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4031 ok(hbm != NULL, "failed to create bitmap\n");
4032 r = ImageList_Add(himl, hbm, 0);
4033 expect(1, r);
4035 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4036 expect(0, r);
4038 item.mask = LVIF_STATE;
4039 item.state = INDEXTOSTATEIMAGEMASK(1);
4040 item.stateMask = LVIS_STATEIMAGEMASK;
4041 item.iItem = 0;
4042 item.iSubItem = 0;
4043 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4044 expect(TRUE, r);
4046 /* icon bounds */
4047 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4048 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4049 expect(TRUE, r);
4050 /* padding + stateicon width */
4051 expect(18, rect.left);
4052 expect(18, rect.right);
4053 /* label bounds */
4054 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4055 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4056 expect(TRUE, r);
4057 /* padding + stateicon width -> column width */
4058 expect(18, rect.left);
4059 expect(50, rect.right);
4061 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4062 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4064 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4065 expect(0, r);
4067 item.mask = LVIF_STATE | LVIF_IMAGE;
4068 item.iImage = 1;
4069 item.state = 0;
4070 item.stateMask = ~0;
4071 item.iItem = 0;
4072 item.iSubItem = 0;
4073 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4074 expect(TRUE, r);
4076 /* icon bounds */
4077 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4078 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4079 expect(TRUE, r);
4080 /* padding, icon width */
4081 expect(2, rect.left);
4082 expect(18, rect.right);
4083 /* label bounds */
4084 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4085 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4086 expect(TRUE, r);
4087 /* padding + icon width -> column width */
4088 expect(18, rect.left);
4089 expect(50, rect.right);
4091 /* select bounds */
4092 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4093 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4094 expect(TRUE, r);
4095 /* padding, column width */
4096 expect(2, rect.left);
4097 expect(50, rect.right);
4099 /* try with indentation */
4100 item.mask = LVIF_INDENT;
4101 item.iIndent = 1;
4102 item.iItem = 0;
4103 item.iSubItem = 0;
4104 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4105 expect(TRUE, r);
4107 /* bounds */
4108 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4109 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4110 expect(TRUE, r);
4111 /* padding + 1 icon width, column width */
4112 expect(0, rect.left);
4113 expect(150, rect.right);
4115 /* select bounds */
4116 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4117 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4118 expect(TRUE, r);
4119 /* padding + 1 icon width, column width */
4120 expect(2 + 16, rect.left);
4121 expect(50, rect.right);
4123 /* label bounds */
4124 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4125 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4126 expect(TRUE, r);
4127 /* padding + 2 icon widths, column width */
4128 expect(2 + 16*2, rect.left);
4129 expect(50, rect.right);
4131 /* icon bounds */
4132 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4133 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4134 expect(TRUE, r);
4135 /* padding + 1 icon width indentation, icon width */
4136 expect(2 + 16, rect.left);
4137 expect(34, rect.right);
4139 DestroyWindow(hwnd);
4142 static void test_editbox(void)
4144 static CHAR testitemA[] = "testitem";
4145 static CHAR testitem1A[] = "testitem_quitelongname";
4146 static CHAR testitem2A[] = "testITEM_quitelongname";
4147 static CHAR buffer[25];
4148 HWND hwnd, hwndedit, hwndedit2, header;
4149 LVITEMA item;
4150 INT r;
4152 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4153 ok(hwnd != NULL, "failed to create a listview window\n");
4155 insert_column(hwnd, 0);
4157 memset(&item, 0, sizeof(item));
4158 item.mask = LVIF_TEXT;
4159 item.pszText = testitemA;
4160 item.iItem = 0;
4161 item.iSubItem = 0;
4162 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4163 expect(0, r);
4165 /* test notifications without edit created */
4166 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4167 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4168 expect(0, r);
4169 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4170 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4171 /* same thing but with valid window */
4172 hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4173 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4174 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4175 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4176 expect(0, r);
4177 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4178 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4179 DestroyWindow(hwndedit);
4181 /* setting focus is necessary */
4182 SetFocus(hwnd);
4183 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4184 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4186 /* test children Z-order after Edit box created */
4187 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4188 ok(IsWindow(header), "Expected header to be created\n");
4189 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4190 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4192 /* modify initial string */
4193 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4194 expect(TRUE, r);
4196 /* edit window is resized and repositioned,
4197 check again for Z-order - it should be preserved */
4198 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4199 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4201 /* return focus to listview */
4202 SetFocus(hwnd);
4204 memset(&item, 0, sizeof(item));
4205 item.mask = LVIF_TEXT;
4206 item.pszText = buffer;
4207 item.cchTextMax = sizeof(buffer);
4208 item.iItem = 0;
4209 item.iSubItem = 0;
4210 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4211 expect(TRUE, r);
4213 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4215 /* send LVM_EDITLABEL on already created edit */
4216 SetFocus(hwnd);
4217 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4218 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4219 /* focus will be set to edit */
4220 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4221 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4222 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4224 /* creating label disabled when control isn't focused */
4225 SetFocus(0);
4226 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4227 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4229 /* check EN_KILLFOCUS handling */
4230 memset(&item, 0, sizeof(item));
4231 item.pszText = testitemA;
4232 item.iItem = 0;
4233 item.iSubItem = 0;
4234 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4235 expect(TRUE, r);
4237 SetFocus(hwnd);
4238 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4239 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4240 /* modify edit and notify control that it lost focus */
4241 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4242 expect(TRUE, r);
4243 g_editbox_disp_info.item.pszText = NULL;
4244 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4245 expect(0, r);
4246 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4248 memset(&item, 0, sizeof(item));
4249 item.pszText = buffer;
4250 item.cchTextMax = sizeof(buffer);
4251 item.iItem = 0;
4252 item.iSubItem = 0;
4253 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4254 expect(lstrlenA(item.pszText), r);
4255 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4256 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4258 /* change item name to differ in casing only */
4259 SetFocus(hwnd);
4260 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4261 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4262 /* modify edit and notify control that it lost focus */
4263 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4264 expect(TRUE, r);
4265 g_editbox_disp_info.item.pszText = NULL;
4266 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4267 expect(0, r);
4268 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4270 memset(&item, 0, sizeof(item));
4271 item.pszText = buffer;
4272 item.cchTextMax = sizeof(buffer);
4273 item.iItem = 0;
4274 item.iSubItem = 0;
4275 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4276 expect(lstrlenA(item.pszText), r);
4277 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4278 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4280 /* end edit without saving */
4281 SetFocus(hwnd);
4282 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4283 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4284 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4285 expect(0, r);
4286 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4287 "edit box - end edit, no change, escape", TRUE);
4288 /* end edit with saving */
4289 SetFocus(hwnd);
4290 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4291 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4292 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4293 expect(0, r);
4294 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4295 "edit box - end edit, no change, return", TRUE);
4297 memset(&item, 0, sizeof(item));
4298 item.pszText = buffer;
4299 item.cchTextMax = sizeof(buffer);
4300 item.iItem = 0;
4301 item.iSubItem = 0;
4302 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4303 expect(lstrlenA(item.pszText), r);
4304 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4306 /* LVM_EDITLABEL with -1 destroys current edit */
4307 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4308 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4309 /* no edit present */
4310 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4311 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4312 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4313 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4314 /* edit present */
4315 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4316 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4317 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4318 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4319 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4320 /* check another negative value */
4321 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4322 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4323 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4324 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4325 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4326 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4327 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4328 /* and value greater than max item index */
4329 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4330 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4331 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4332 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4333 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4334 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4335 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4336 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4338 /* messaging tests */
4339 SetFocus(hwnd);
4340 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4341 blockEdit = FALSE;
4342 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4343 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4344 /* testing only sizing messages */
4345 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4346 "edit box create - sizing", FALSE);
4348 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4349 SetFocus(hwnd);
4350 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4351 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4352 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4353 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4354 expect(0, r);
4355 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4356 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4358 DestroyWindow(hwnd);
4361 static void test_notifyformat(void)
4363 HWND hwnd, header;
4364 DWORD r;
4366 hwnd = create_listview_control(LVS_REPORT);
4367 ok(hwnd != NULL, "failed to create a listview window\n");
4369 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4370 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4371 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4372 expect(0, r);
4373 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4374 /* set */
4375 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4376 expect(0, r);
4377 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4378 if (r == 1)
4380 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4381 expect(1, r);
4382 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4383 expect(0, r);
4385 else
4387 win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
4388 DestroyWindow(hwnd);
4389 return;
4392 DestroyWindow(hwnd);
4394 /* test failure in parent WM_NOTIFYFORMAT */
4395 notifyFormat = 0;
4396 hwnd = create_listview_control(LVS_REPORT);
4397 ok(hwnd != NULL, "failed to create a listview window\n");
4398 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4399 ok(IsWindow(header), "expected header to be created\n");
4400 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4401 expect(0, r);
4402 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4403 ok( r == 1, "Expected 1, got %d\n", r );
4404 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4405 ok(r != 0, "Expected valid format\n");
4407 notifyFormat = NFR_UNICODE;
4408 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4409 expect(NFR_UNICODE, r);
4410 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4411 expect(1, r);
4412 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4413 ok( r == 1, "Expected 1, got %d\n", r );
4415 notifyFormat = NFR_ANSI;
4416 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4417 expect(NFR_ANSI, r);
4418 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4419 expect(0, r);
4420 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4421 ok( r == 1, "Expected 1, got %d\n", r );
4423 DestroyWindow(hwnd);
4425 hwndparentW = create_parent_window(TRUE);
4426 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4427 if (!IsWindow(hwndparentW)) return;
4429 notifyFormat = -1;
4430 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
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(1, r);
4436 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4437 expect(1, r);
4438 DestroyWindow(hwnd);
4439 /* receiving error code defaulting to ansi */
4440 notifyFormat = 0;
4441 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4442 ok(hwnd != NULL, "failed to create a listview window\n");
4443 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4444 ok(IsWindow(header), "expected header to be created\n");
4445 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4446 expect(0, r);
4447 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4448 expect(1, r);
4449 DestroyWindow(hwnd);
4450 /* receiving ansi code from unicode window, use it */
4451 notifyFormat = NFR_ANSI;
4452 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4453 ok(hwnd != NULL, "failed to create a listview window\n");
4454 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4455 ok(IsWindow(header), "expected header to be created\n");
4456 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4457 expect(0, r);
4458 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4459 expect(1, r);
4460 DestroyWindow(hwnd);
4461 /* unicode listview with ansi parent window */
4462 notifyFormat = -1;
4463 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4464 ok(hwnd != NULL, "failed to create a listview window\n");
4465 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4466 ok(IsWindow(header), "expected header to be created\n");
4467 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4468 expect(0, r);
4469 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4470 expect(1, r);
4471 DestroyWindow(hwnd);
4472 /* unicode listview with ansi parent window, return error code */
4473 notifyFormat = 0;
4474 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4475 ok(hwnd != NULL, "failed to create a listview window\n");
4476 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4477 ok(IsWindow(header), "expected header to be created\n");
4478 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4479 expect(0, r);
4480 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4481 expect(1, r);
4482 DestroyWindow(hwnd);
4484 DestroyWindow(hwndparentW);
4487 static void test_indentation(void)
4489 HWND hwnd;
4490 LVITEMA item;
4491 DWORD r;
4493 hwnd = create_listview_control(LVS_REPORT);
4494 ok(hwnd != NULL, "failed to create a listview window\n");
4496 memset(&item, 0, sizeof(item));
4497 item.mask = LVIF_INDENT;
4498 item.iItem = 0;
4499 item.iIndent = I_INDENTCALLBACK;
4500 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4501 expect(0, r);
4503 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4505 item.iItem = 0;
4506 item.mask = LVIF_INDENT;
4507 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4508 expect(TRUE, r);
4510 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4511 "get indent dispinfo", FALSE);
4513 DestroyWindow(hwnd);
4516 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4518 return 0;
4521 static BOOL is_below_comctl_5(void)
4523 HWND hwnd;
4524 BOOL ret;
4526 hwnd = create_listview_control(LVS_REPORT);
4527 ok(hwnd != NULL, "failed to create a listview window\n");
4528 insert_item(hwnd, 0);
4530 ret = SendMessageA(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4532 DestroyWindow(hwnd);
4534 return !ret;
4537 static void test_get_set_view(void)
4539 HWND hwnd;
4540 DWORD ret;
4541 DWORD_PTR style;
4543 /* test style->view mapping */
4544 hwnd = create_listview_control(LVS_REPORT);
4545 ok(hwnd != NULL, "failed to create a listview window\n");
4547 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4548 expect(LV_VIEW_DETAILS, ret);
4550 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4551 /* LVS_ICON == 0 */
4552 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4553 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4554 expect(LV_VIEW_ICON, ret);
4556 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4557 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4558 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4559 expect(LV_VIEW_SMALLICON, ret);
4561 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4562 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4563 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4564 expect(LV_VIEW_LIST, ret);
4566 /* switching view doesn't touch window style */
4567 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4568 expect(1, ret);
4569 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4570 ok(style & LVS_LIST, "Expected style to be preserved\n");
4571 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4572 expect(1, ret);
4573 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4574 ok(style & LVS_LIST, "Expected style to be preserved\n");
4575 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4576 expect(1, ret);
4577 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4578 ok(style & LVS_LIST, "Expected style to be preserved\n");
4580 /* now change window style to see if view is remapped */
4581 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4582 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4583 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4584 expect(LV_VIEW_SMALLICON, ret);
4586 DestroyWindow(hwnd);
4589 static void test_canceleditlabel(void)
4591 HWND hwnd, hwndedit;
4592 DWORD ret;
4593 CHAR buff[10];
4594 LVITEMA itema;
4595 static CHAR test[] = "test";
4596 static const CHAR test1[] = "test1";
4598 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4599 ok(hwnd != NULL, "failed to create a listview window\n");
4601 insert_item(hwnd, 0);
4603 /* try without edit created */
4604 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4605 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4606 expect(TRUE, ret);
4607 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4608 "cancel edit label without edit", FALSE);
4610 /* cancel without data change */
4611 SetFocus(hwnd);
4612 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4613 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4614 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4615 expect(TRUE, ret);
4616 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4618 /* cancel after data change */
4619 memset(&itema, 0, sizeof(itema));
4620 itema.pszText = test;
4621 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4622 expect(TRUE, ret);
4623 SetFocus(hwnd);
4624 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4625 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4626 ret = SetWindowTextA(hwndedit, test1);
4627 expect(1, ret);
4628 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4629 expect(TRUE, ret);
4630 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4631 memset(&itema, 0, sizeof(itema));
4632 itema.pszText = buff;
4633 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
4634 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4635 expect(5, ret);
4636 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4638 DestroyWindow(hwnd);
4641 static void test_mapidindex(void)
4643 HWND hwnd;
4644 INT ret;
4646 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4647 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4648 ok(hwnd != NULL, "failed to create a listview window\n");
4649 insert_item(hwnd, 0);
4650 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4651 expect(-1, ret);
4652 DestroyWindow(hwnd);
4654 hwnd = create_listview_control(LVS_REPORT);
4655 ok(hwnd != NULL, "failed to create a listview window\n");
4657 /* LVM_MAPINDEXTOID with invalid index */
4658 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4659 expect(-1, ret);
4661 insert_item(hwnd, 0);
4662 insert_item(hwnd, 1);
4664 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4665 expect(-1, ret);
4666 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4667 expect(-1, ret);
4669 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4670 expect(0, ret);
4671 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4672 expect(1, ret);
4673 /* remove 0 indexed item, id retained */
4674 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4675 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4676 expect(1, ret);
4677 /* new id starts from previous value */
4678 insert_item(hwnd, 1);
4679 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4680 expect(2, ret);
4682 /* get index by id */
4683 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4684 expect(-1, ret);
4685 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4686 expect(-1, ret);
4687 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4688 expect(0, ret);
4689 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4690 expect(1, ret);
4692 DestroyWindow(hwnd);
4695 static void test_getitemspacing(void)
4697 HWND hwnd;
4698 DWORD ret;
4699 INT cx, cy;
4700 HIMAGELIST himl40, himl80;
4702 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4703 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4705 /* LVS_ICON */
4706 hwnd = create_listview_control(LVS_ICON);
4707 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4708 expect(cx, LOWORD(ret));
4709 expect(cy, HIWORD(ret));
4711 /* now try with icons */
4712 himl40 = ImageList_Create(40, 40, 0, 4, 4);
4713 ok(himl40 != NULL, "failed to create imagelist\n");
4714 himl80 = ImageList_Create(80, 80, 0, 4, 4);
4715 ok(himl80 != NULL, "failed to create imagelist\n");
4716 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4717 expect(0, ret);
4719 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4720 /* spacing + icon size returned */
4721 expect(cx + 40, LOWORD(ret));
4722 expect(cy + 40, HIWORD(ret));
4723 /* try changing icon size */
4724 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4726 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4727 /* spacing + icon size returned */
4728 expect(cx + 80, LOWORD(ret));
4729 expect(cy + 80, HIWORD(ret));
4731 /* set own icon spacing */
4732 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4733 expect(cx + 80, LOWORD(ret));
4734 expect(cy + 80, HIWORD(ret));
4736 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4737 /* set size returned */
4738 expect(100, LOWORD(ret));
4739 expect(100, HIWORD(ret));
4741 /* now change image list - icon spacing should be unaffected */
4742 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4744 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4745 /* set size returned */
4746 expect(100, LOWORD(ret));
4747 expect(100, HIWORD(ret));
4749 /* spacing = 0 - keep previous value */
4750 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
4751 expect(100, LOWORD(ret));
4752 expect(100, HIWORD(ret));
4754 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4755 expect(100, LOWORD(ret));
4757 expect(0xFFFF, HIWORD(ret));
4759 if (sizeof(void*) == 8)
4761 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
4762 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
4763 expect(100, LOWORD(ret));
4764 expect(0xFFFF, HIWORD(ret));
4766 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4767 expect(0xFFFF, LOWORD(ret));
4768 expect(0xFFFF, HIWORD(ret));
4770 else
4772 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4773 expect(100, LOWORD(ret));
4774 expect(0xFFFF, HIWORD(ret));
4776 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4777 /* spacing + icon size returned */
4778 expect(cx + 40, LOWORD(ret));
4779 expect(cy + 40, HIWORD(ret));
4781 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4782 ImageList_Destroy(himl80);
4783 DestroyWindow(hwnd);
4784 /* LVS_SMALLICON */
4785 hwnd = create_listview_control(LVS_SMALLICON);
4786 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4787 expect(cx, LOWORD(ret));
4788 expect(cy, HIWORD(ret));
4790 /* spacing does not depend on selected view type */
4791 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4792 expect(0, ret);
4794 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4795 /* spacing + icon size returned */
4796 expect(cx + 40, LOWORD(ret));
4797 expect(cy + 40, HIWORD(ret));
4799 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4800 ImageList_Destroy(himl40);
4801 DestroyWindow(hwnd);
4802 /* LVS_REPORT */
4803 hwnd = create_listview_control(LVS_REPORT);
4804 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4805 expect(cx, LOWORD(ret));
4806 expect(cy, HIWORD(ret));
4808 DestroyWindow(hwnd);
4809 /* LVS_LIST */
4810 hwnd = create_listview_control(LVS_LIST);
4811 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4812 expect(cx, LOWORD(ret));
4813 expect(cy, HIWORD(ret));
4815 DestroyWindow(hwnd);
4818 static INT get_current_font_height(HWND listview)
4820 TEXTMETRICA tm;
4821 HFONT hfont;
4822 HWND hwnd;
4823 HDC hdc;
4825 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
4826 if (!hwnd)
4827 hwnd = listview;
4829 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
4830 if (!hfont) {
4831 hdc = GetDC(hwnd);
4832 GetTextMetricsA(hdc, &tm);
4833 ReleaseDC(hwnd, hdc);
4835 else {
4836 HFONT oldfont;
4838 hdc = GetDC(0);
4839 oldfont = SelectObject(hdc, hfont);
4840 GetTextMetricsA(hdc, &tm);
4841 SelectObject(hdc, oldfont);
4842 ReleaseDC(0, hdc);
4845 return tm.tmHeight;
4848 static void test_getcolumnwidth(void)
4850 HWND hwnd;
4851 INT ret;
4852 DWORD_PTR style;
4853 LVCOLUMNA col;
4854 LVITEMA itema;
4855 INT height;
4857 /* default column width */
4858 hwnd = create_listview_control(LVS_ICON);
4859 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4860 expect(0, ret);
4861 style = GetWindowLongA(hwnd, GWL_STYLE);
4862 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
4863 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4864 todo_wine expect(8, ret);
4865 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
4866 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
4867 col.mask = 0;
4868 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4869 expect(0, ret);
4870 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4871 expect(10, ret);
4872 DestroyWindow(hwnd);
4874 /* default column width with item added */
4875 hwnd = create_listview_control(LVS_LIST);
4876 memset(&itema, 0, sizeof(itema));
4877 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4878 ok(!ret, "got %d\n", ret);
4879 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4880 height = get_current_font_height(hwnd);
4881 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
4882 DestroyWindow(hwnd);
4885 static void test_scrollnotify(void)
4887 HWND hwnd;
4888 DWORD ret;
4890 hwnd = create_listview_control(LVS_REPORT);
4892 insert_column(hwnd, 0);
4893 insert_column(hwnd, 1);
4894 insert_item(hwnd, 0);
4896 /* make it scrollable - resize */
4897 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4898 expect(TRUE, ret);
4899 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4900 expect(TRUE, ret);
4902 /* try with dummy call */
4903 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4904 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
4905 expect(TRUE, ret);
4906 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4907 "scroll notify 1", TRUE);
4909 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4910 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
4911 expect(TRUE, ret);
4912 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4913 "scroll notify 2", TRUE);
4915 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4916 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
4917 expect(TRUE, ret);
4918 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4919 "scroll notify 3", TRUE);
4921 DestroyWindow(hwnd);
4924 static void test_LVS_EX_TRANSPARENTBKGND(void)
4926 HWND hwnd;
4927 DWORD ret;
4928 HDC hdc;
4930 hwnd = create_listview_control(LVS_REPORT);
4932 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4933 expect(TRUE, ret);
4935 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4936 LVS_EX_TRANSPARENTBKGND);
4938 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
4939 if (ret != CLR_NONE)
4941 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4942 DestroyWindow(hwnd);
4943 return;
4946 /* try to set some back color and check this style bit */
4947 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4948 expect(TRUE, ret);
4949 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4950 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4952 /* now test what this style actually does */
4953 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4954 LVS_EX_TRANSPARENTBKGND);
4956 hdc = GetWindowDC(hwndparent);
4958 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4959 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4960 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4961 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4963 ReleaseDC(hwndparent, hdc);
4965 DestroyWindow(hwnd);
4968 static void test_approximate_viewrect(void)
4970 HWND hwnd;
4971 DWORD ret;
4972 HIMAGELIST himl;
4973 HBITMAP hbmp;
4974 LVITEMA itema;
4975 static CHAR test[] = "abracadabra, a very long item label";
4977 hwnd = create_listview_control(LVS_ICON);
4978 himl = ImageList_Create(40, 40, 0, 4, 4);
4979 ok(himl != NULL, "failed to create imagelist\n");
4980 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4981 ok(hbmp != NULL, "failed to create bitmap\n");
4982 ret = ImageList_Add(himl, hbmp, 0);
4983 expect(0, ret);
4984 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4985 expect(0, ret);
4987 itema.mask = LVIF_IMAGE;
4988 itema.iImage = 0;
4989 itema.iItem = 0;
4990 itema.iSubItem = 0;
4991 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4992 expect(0, ret);
4994 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
4995 if (ret == 0)
4997 /* version 4.0 */
4998 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
4999 return;
5002 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5003 expect(MAKELONG(77,827), ret);
5005 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5006 ok(ret != 0, "got 0\n");
5008 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5009 expect(MAKELONG(102,302), ret);
5011 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5012 expect(MAKELONG(52,52), ret);
5014 itema.pszText = test;
5015 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5016 expect(TRUE, ret);
5017 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5018 expect(MAKELONG(52,52), ret);
5020 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5021 expect(MAKELONG(52,2), ret);
5022 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5023 expect(MAKELONG(52,52), ret);
5024 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5025 expect(MAKELONG(102,52), ret);
5026 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5027 expect(MAKELONG(102,102), ret);
5028 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5029 expect(MAKELONG(102,102), ret);
5030 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5031 expect(MAKELONG(102,152), ret);
5032 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5033 expect(MAKELONG(102,152), ret);
5034 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5035 expect(MAKELONG(152,152), ret);
5037 DestroyWindow(hwnd);
5040 static void test_finditem(void)
5042 LVFINDINFOA fi;
5043 static char f[5];
5044 HWND hwnd;
5045 INT r;
5047 hwnd = create_listview_control(LVS_REPORT);
5048 insert_item(hwnd, 0);
5050 memset(&fi, 0, sizeof(fi));
5052 /* full string search, inserted text was "foo" */
5053 strcpy(f, "foo");
5054 fi.flags = LVFI_STRING;
5055 fi.psz = f;
5056 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5057 expect(0, r);
5058 /* partial string search, inserted text was "foo" */
5059 strcpy(f, "fo");
5060 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5061 fi.psz = f;
5062 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5063 expect(0, r);
5064 /* partial string search, part after start char */
5065 strcpy(f, "oo");
5066 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5067 fi.psz = f;
5068 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5069 expect(-1, r);
5071 /* try with LVFI_SUBSTRING */
5072 strcpy(f, "fo");
5073 fi.flags = LVFI_SUBSTRING;
5074 fi.psz = f;
5075 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5076 if (r == -1)
5078 win_skip("LVFI_SUBSTRING not supported\n");
5079 DestroyWindow(hwnd);
5080 return;
5082 expect(0, r);
5083 strcpy(f, "f");
5084 fi.flags = LVFI_SUBSTRING;
5085 fi.psz = f;
5086 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5087 expect(0, r);
5088 strcpy(f, "o");
5089 fi.flags = LVFI_SUBSTRING;
5090 fi.psz = f;
5091 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5092 expect(-1, r);
5094 strcpy(f, "f");
5095 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5096 fi.psz = f;
5097 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5098 expect(0, r);
5100 DestroyWindow(hwnd);
5103 static void test_LVS_EX_HEADERINALLVIEWS(void)
5105 HWND hwnd, header;
5106 DWORD style;
5108 hwnd = create_listview_control(LVS_ICON);
5110 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5111 LVS_EX_HEADERINALLVIEWS);
5113 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5114 if (!IsWindow(header))
5116 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5117 DestroyWindow(hwnd);
5118 return;
5121 /* LVS_NOCOLUMNHEADER works as before */
5122 style = GetWindowLongA(hwnd, GWL_STYLE);
5123 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5124 style = GetWindowLongA(header, GWL_STYLE);
5125 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5126 style = GetWindowLongA(hwnd, GWL_STYLE);
5127 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5128 style = GetWindowLongA(header, GWL_STYLE);
5129 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5131 /* try to remove style */
5132 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5133 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5134 ok(IsWindow(header), "Expected header to be created\n");
5135 style = GetWindowLongA(header, GWL_STYLE);
5136 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5138 DestroyWindow(hwnd);
5140 /* check other styles */
5141 hwnd = create_listview_control(LVS_LIST);
5142 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5143 LVS_EX_HEADERINALLVIEWS);
5144 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5145 ok(IsWindow(header), "Expected header to be created\n");
5146 DestroyWindow(hwnd);
5148 hwnd = create_listview_control(LVS_SMALLICON);
5149 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5150 LVS_EX_HEADERINALLVIEWS);
5151 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5152 ok(IsWindow(header), "Expected header to be created\n");
5153 DestroyWindow(hwnd);
5155 hwnd = create_listview_control(LVS_REPORT);
5156 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5157 LVS_EX_HEADERINALLVIEWS);
5158 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5159 ok(IsWindow(header), "Expected header to be created\n");
5160 DestroyWindow(hwnd);
5163 static void test_hover(void)
5165 HWND hwnd, fg;
5166 DWORD r;
5168 hwnd = create_listview_control(LVS_ICON);
5169 SetForegroundWindow(hwndparent);
5170 fg = GetForegroundWindow();
5171 if (fg != hwndparent)
5173 skip("Window is not in the foreground. Skipping hover tests.\n");
5174 DestroyWindow(hwnd);
5175 return;
5178 /* test WM_MOUSEHOVER forwarding */
5179 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5180 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5181 expect(0, r);
5182 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5183 g_block_hover = TRUE;
5184 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5185 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5186 expect(0, r);
5187 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5188 g_block_hover = FALSE;
5190 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5191 expect(HOVER_DEFAULT, r);
5192 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5193 expect(500, r);
5195 DestroyWindow(hwnd);
5198 static void test_destroynotify(void)
5200 HWND hwnd;
5201 BOOL ret;
5203 hwnd = create_listview_control(LVS_REPORT);
5204 ok(hwnd != NULL, "failed to create listview window\n");
5206 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5207 DestroyWindow(hwnd);
5208 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5210 /* same for ownerdata list */
5211 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5212 ok(hwnd != NULL, "failed to create listview window\n");
5214 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5215 DestroyWindow(hwnd);
5216 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5218 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5219 ok(hwnd != NULL, "failed to create listview window\n");
5221 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5222 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5223 ok(ret == TRUE, "got %d\n", ret);
5224 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5225 DestroyWindow(hwnd);
5228 static void test_header_notification(void)
5230 static char textA[] = "newtext";
5231 HWND list, header;
5232 HDITEMA item;
5233 NMHEADERA nmh;
5234 LVCOLUMNA col;
5235 DWORD ret;
5236 BOOL r;
5238 list = create_listview_control(LVS_REPORT);
5239 ok(list != NULL, "failed to create listview window\n");
5241 memset(&col, 0, sizeof(col));
5242 col.mask = LVCF_WIDTH;
5243 col.cx = 100;
5244 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5245 expect(0, ret);
5247 /* check list parent notification after header item changed,
5248 this test should be placed before header subclassing to avoid
5249 Listview -> Header messages to be logged */
5250 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5252 col.mask = LVCF_TEXT;
5253 col.pszText = textA;
5254 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5255 expect(TRUE, r);
5257 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5258 "header notify, listview", FALSE);
5259 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5260 "header notify, parent", FALSE);
5262 header = subclass_header(list);
5264 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5265 expect(1, ret);
5267 memset(&item, 0, sizeof(item));
5268 item.mask = HDI_WIDTH;
5269 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5270 expect(1, ret);
5271 expect(100, item.cxy);
5273 nmh.hdr.hwndFrom = header;
5274 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5275 nmh.hdr.code = HDN_ITEMCHANGEDA;
5276 nmh.iItem = 0;
5277 nmh.iButton = 0;
5278 item.mask = HDI_WIDTH;
5279 item.cxy = 50;
5280 nmh.pitem = &item;
5281 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5282 expect(0, ret);
5284 DestroyWindow(list);
5287 static void test_header_notification2(void)
5289 static char textA[] = "newtext";
5290 HWND list, header;
5291 HDITEMW itemW;
5292 NMHEADERW nmhdr;
5293 LVCOLUMNA col;
5294 DWORD ret;
5295 WCHAR buffer[100];
5296 struct message parent_header_notify_seq[] = {
5297 { WM_NOTIFY, sent|id, 0, 0, 0 },
5298 { 0 }
5301 list = create_listview_control(LVS_REPORT);
5302 ok(list != NULL, "failed to create listview window\n");
5304 memset(&col, 0, sizeof(col));
5305 col.mask = LVCF_WIDTH | LVCF_TEXT;
5306 col.cx = 100;
5307 col.pszText = textA;
5308 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5309 expect(0, ret);
5311 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5312 ok(header != 0, "No header\n");
5313 memset(&itemW, 0, sizeof(itemW));
5314 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5315 itemW.pszText = buffer;
5316 itemW.cchTextMax = sizeof(buffer);
5317 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5318 expect(1, ret);
5320 nmhdr.hdr.hwndFrom = header;
5321 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5322 nmhdr.iItem = 0;
5323 nmhdr.iButton = 0;
5324 nmhdr.pitem = &itemW;
5326 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5327 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5328 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5329 ok(ret == 0, "got %d\n", ret);
5330 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5331 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5332 "header notify, parent", TRUE);
5333 todo_wine
5334 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5335 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5336 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5337 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5338 ok(ret == 0, "got %d\n", ret);
5339 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5340 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5341 "header notify, parent", TRUE);
5342 todo_wine
5343 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5344 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5345 SetFocus(list);
5346 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5347 nmhdr.hdr.code = HDN_ITEMCLICKW;
5348 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5349 ok(ret == 0, "got %d\n", ret);
5350 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5351 "header notify, parent", FALSE);
5352 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5353 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5354 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5355 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5356 ok(ret == 0, "got %d\n", ret);
5357 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5358 "header notify, parent", FALSE);
5359 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5360 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5361 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5362 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5363 ok(ret == 0, "got %d\n", ret);
5364 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5365 "header notify, parent", TRUE);
5366 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5367 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5368 nmhdr.hdr.code = HDN_BEGINTRACKW;
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 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5374 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5375 nmhdr.hdr.code = HDN_ENDTRACKW;
5376 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5377 ok(ret == 0, "got %d\n", ret);
5378 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5379 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5380 "header notify, parent", FALSE);
5381 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5382 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5383 nmhdr.hdr.code = HDN_TRACKW;
5384 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5385 ok(ret == 0, "got %d\n", ret);
5386 parent_header_notify_seq[0].id = HDN_TRACKA;
5387 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5388 "header notify, parent", FALSE);
5389 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5390 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5391 nmhdr.hdr.code = HDN_BEGINDRAG;
5392 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5393 ok(ret == 1, "got %d\n", ret);
5394 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5395 "header notify, parent", FALSE);
5396 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5397 nmhdr.hdr.code = HDN_ENDDRAG;
5398 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5399 ok(ret == 0, "got %d\n", ret);
5400 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5401 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5402 "header notify, parent", FALSE);
5403 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5404 nmhdr.hdr.code = HDN_FILTERCHANGE;
5405 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5406 ok(ret == 0, "got %d\n", ret);
5407 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5408 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5409 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5410 "header notify, parent", FALSE);
5411 parent_header_notify_seq[0].flags &= ~optional;
5412 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5413 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5414 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5415 ok(ret == 0, "got %d\n", ret);
5416 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5417 "header notify, parent", FALSE);
5418 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5419 nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5420 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5421 ok(ret == 0, "got %d\n", ret);
5422 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5423 "header notify, parent", FALSE);
5424 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5425 nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5426 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5427 ok(ret == 0, "got %d\n", ret);
5428 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5429 "header notify, parent", FALSE);
5430 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5431 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5432 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5433 ok(ret == 0, "got %d\n", ret);
5434 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5435 "header notify, parent", FALSE);
5437 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5439 DestroyWindow(list);
5442 static void test_createdragimage(void)
5444 HIMAGELIST himl;
5445 POINT pt;
5446 HWND list;
5448 list = create_listview_control(LVS_ICON);
5449 ok(list != NULL, "failed to create listview window\n");
5451 insert_item(list, 0);
5453 /* NULL point */
5454 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5455 ok(himl == NULL, "got %p\n", himl);
5457 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5458 ok(himl != NULL, "got %p\n", himl);
5459 ImageList_Destroy(himl);
5461 DestroyWindow(list);
5464 static void test_dispinfo(void)
5466 static const char testA[] = "TEST";
5467 WCHAR buff[10];
5468 LVITEMA item;
5469 HWND hwnd;
5470 DWORD ret;
5472 hwnd = create_listview_control(LVS_ICON);
5473 ok(hwnd != NULL, "failed to create listview window\n");
5475 insert_item(hwnd, 0);
5477 memset(&item, 0, sizeof(item));
5478 item.pszText = LPSTR_TEXTCALLBACKA;
5479 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5480 expect(1, ret);
5482 g_disp_A_to_W = TRUE;
5483 item.pszText = (char*)buff;
5484 item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
5485 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5486 ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
5487 g_disp_A_to_W = FALSE;
5489 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5490 "got %s, expected %s\n", item.pszText, testA);
5492 DestroyWindow(hwnd);
5495 static void test_LVM_SETITEMTEXT(void)
5497 static char testA[] = "TEST";
5498 LVITEMA item;
5499 HWND hwnd;
5500 DWORD ret;
5502 hwnd = create_listview_control(LVS_ICON);
5503 ok(hwnd != NULL, "failed to create listview window\n");
5505 insert_item(hwnd, 0);
5507 /* null item pointer */
5508 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5509 expect(FALSE, ret);
5511 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5512 expect(FALSE, ret);
5514 /* index out of bounds */
5515 item.pszText = testA;
5516 item.cchTextMax = 0; /* ignored */
5517 item.iSubItem = 0;
5519 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5520 expect(FALSE, ret);
5522 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5523 expect(FALSE, ret);
5525 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5526 expect(TRUE, ret);
5528 DestroyWindow(hwnd);
5531 static void test_LVM_REDRAWITEMS(void)
5533 HWND list;
5534 DWORD ret;
5536 list = create_listview_control(LVS_ICON);
5537 ok(list != NULL, "failed to create listview window\n");
5539 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5540 expect(TRUE, ret);
5542 insert_item(list, 0);
5544 ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
5545 expect(TRUE, ret);
5547 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
5548 expect(TRUE, ret);
5550 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5551 expect(TRUE, ret);
5553 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
5554 expect(TRUE, ret);
5556 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
5557 expect(TRUE, ret);
5559 ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
5560 expect(TRUE, ret);
5562 ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
5563 expect(TRUE, ret);
5565 DestroyWindow(list);
5568 static void test_imagelists(void)
5570 HWND hwnd, header;
5571 HIMAGELIST himl1, himl2, himl3;
5572 LRESULT ret;
5574 himl1 = ImageList_Create(40, 40, 0, 4, 4);
5575 himl2 = ImageList_Create(40, 40, 0, 4, 4);
5576 himl3 = ImageList_Create(40, 40, 0, 4, 4);
5577 ok(himl1 != NULL, "Failed to create imagelist\n");
5578 ok(himl2 != NULL, "Failed to create imagelist\n");
5579 ok(himl3 != NULL, "Failed to create imagelist\n");
5581 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5582 header = subclass_header(hwnd);
5584 ok(header != NULL, "Expected header\n");
5585 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5586 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5588 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5590 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5591 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5592 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5593 "set normal image list", FALSE);
5595 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5597 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5598 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5599 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5600 "set state image list", TRUE);
5602 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5603 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5605 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5607 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5608 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5609 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
5610 "set small image list", FALSE);
5612 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5613 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5614 DestroyWindow(hwnd);
5616 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
5618 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5620 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5621 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5622 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5623 "set normal image list", FALSE);
5625 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5627 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5628 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5629 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5630 "set state image list", FALSE);
5632 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5634 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5635 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5636 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5637 "set small image list", FALSE);
5639 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5640 ok(header == NULL, "Expected no header, got %p\n", header);
5642 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
5644 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5645 ok(header != NULL, "Expected header, got NULL\n");
5647 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5648 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5650 DestroyWindow(hwnd);
5653 static void test_deleteitem(void)
5655 LVITEMA item;
5656 UINT state;
5657 HWND hwnd;
5658 BOOL ret;
5660 hwnd = create_listview_control(LVS_REPORT);
5662 insert_item(hwnd, 0);
5663 insert_item(hwnd, 0);
5664 insert_item(hwnd, 0);
5665 insert_item(hwnd, 0);
5666 insert_item(hwnd, 0);
5668 g_focus_test_LVN_DELETEITEM = TRUE;
5670 /* delete focused item (not the last index) */
5671 item.stateMask = LVIS_FOCUSED;
5672 item.state = LVIS_FOCUSED;
5673 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
5674 ok(ret == TRUE, "got %d\n", ret);
5675 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
5676 ok(ret == TRUE, "got %d\n", ret);
5677 /* next item gets focus */
5678 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5679 ok(state == LVIS_FOCUSED, "got %x\n", state);
5681 /* focus last item and delete it */
5682 item.stateMask = LVIS_FOCUSED;
5683 item.state = LVIS_FOCUSED;
5684 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
5685 ok(ret == TRUE, "got %d\n", ret);
5686 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
5687 ok(ret == TRUE, "got %d\n", ret);
5688 /* new last item gets focus */
5689 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5690 ok(state == LVIS_FOCUSED, "got %x\n", state);
5692 /* focus first item and delete it */
5693 item.stateMask = LVIS_FOCUSED;
5694 item.state = LVIS_FOCUSED;
5695 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
5696 ok(ret == TRUE, "got %d\n", ret);
5697 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
5698 ok(ret == TRUE, "got %d\n", ret);
5699 /* new first item gets focus */
5700 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5701 ok(state == LVIS_FOCUSED, "got %x\n", state);
5703 g_focus_test_LVN_DELETEITEM = FALSE;
5705 DestroyWindow(hwnd);
5708 static void test_insertitem(void)
5710 LVITEMA item;
5711 UINT state;
5712 HWND hwnd;
5713 INT ret;
5715 hwnd = create_listview_control(LVS_REPORT);
5717 /* insert item 0 focused */
5718 item.mask = LVIF_STATE;
5719 item.state = LVIS_FOCUSED;
5720 item.stateMask = LVIS_FOCUSED;
5721 item.iItem = 0;
5722 item.iSubItem = 0;
5723 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5724 ok(ret == 0, "got %d\n", ret);
5726 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5727 ok(state == LVIS_FOCUSED, "got %x\n", state);
5729 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5731 /* insert item 1, focus shift */
5732 item.mask = LVIF_STATE;
5733 item.state = LVIS_FOCUSED;
5734 item.stateMask = LVIS_FOCUSED;
5735 item.iItem = 1;
5736 item.iSubItem = 0;
5737 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5738 ok(ret == 1, "got %d\n", ret);
5740 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
5742 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5743 ok(state == LVIS_FOCUSED, "got %x\n", state);
5745 /* insert item 2, no focus shift */
5746 item.mask = LVIF_STATE;
5747 item.state = 0;
5748 item.stateMask = LVIS_FOCUSED;
5749 item.iItem = 2;
5750 item.iSubItem = 0;
5751 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5752 ok(ret == 2, "got %d\n", ret);
5754 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5755 ok(state == LVIS_FOCUSED, "got %x\n", state);
5757 DestroyWindow(hwnd);
5760 static void test_header_proc(void)
5762 HWND hwnd, header, hdr;
5763 WNDPROC proc1, proc2;
5765 hwnd = create_listview_control(LVS_REPORT);
5767 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5768 ok(header != NULL, "got %p\n", header);
5770 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
5771 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
5772 0, 0, 0, 0,
5773 NULL, NULL, NULL, NULL);
5774 ok(hdr != NULL, "got %p\n", hdr);
5776 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
5777 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
5778 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
5780 DestroyWindow(hdr);
5781 DestroyWindow(hwnd);
5784 static void flush_events(void)
5786 MSG msg;
5787 int diff = 200;
5788 int min_timeout = 100;
5789 DWORD time = GetTickCount() + diff;
5791 while (diff > 0)
5793 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
5794 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
5795 diff = time - GetTickCount();
5799 static void test_oneclickactivate(void)
5801 TRACKMOUSEEVENT track;
5802 char item1[] = "item1";
5803 LVITEMA item;
5804 HWND hwnd, fg;
5805 RECT rect;
5806 INT r;
5807 POINT orig_pos;
5809 hwnd = CreateWindowExA(0, "SysListView32", "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
5810 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
5811 ok(hwnd != NULL, "failed to create listview window\n");
5812 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
5813 ok(r == 0, "should return zero\n");
5815 SetForegroundWindow(hwndparent);
5816 flush_events();
5817 fg = GetForegroundWindow();
5818 if (fg != hwndparent)
5820 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
5821 DestroyWindow(hwnd);
5822 return;
5825 item.mask = LVIF_TEXT;
5826 item.iItem = 0;
5827 item.iSubItem = 0;
5828 item.iImage = 0;
5829 item.pszText = item1;
5830 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
5831 ok(r == 0, "should not fail\n");
5833 GetWindowRect(hwnd, &rect);
5834 GetCursorPos(&orig_pos);
5835 SetCursorPos(rect.left+5, rect.top+5);
5836 flush_events();
5837 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
5838 expect(0, r);
5840 track.cbSize = sizeof(track);
5841 track.dwFlags = TME_QUERY;
5842 _TrackMouseEvent(&track);
5843 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
5844 ok(track.dwFlags == TME_LEAVE, "dwFlags = %x\n", track.dwFlags);
5846 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5847 expect(0, r);
5848 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
5849 expect(0, r);
5850 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5851 expect(1, r);
5853 DestroyWindow(hwnd);
5854 SetCursorPos(orig_pos.x, orig_pos.y);
5857 static void test_callback_mask(void)
5859 DWORD mask;
5860 HWND hwnd;
5861 BOOL ret;
5863 hwnd = create_listview_control(LVS_REPORT);
5865 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 0);
5866 ok(ret, "got %d\n", ret);
5868 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 1);
5869 ok(ret, "got %d\n", ret);
5871 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
5872 ok(mask == ~0u, "got 0x%08x\n", mask);
5874 DestroyWindow(hwnd);
5877 START_TEST(listview)
5879 HMODULE hComctl32;
5880 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
5882 ULONG_PTR ctx_cookie;
5883 HANDLE hCtx;
5885 hComctl32 = GetModuleHandleA("comctl32.dll");
5886 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
5887 if (pInitCommonControlsEx)
5889 INITCOMMONCONTROLSEX iccex;
5890 iccex.dwSize = sizeof(iccex);
5891 iccex.dwICC = ICC_LISTVIEW_CLASSES;
5892 pInitCommonControlsEx(&iccex);
5894 else
5895 InitCommonControls();
5897 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
5899 hwndparent = create_parent_window(FALSE);
5900 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5902 g_is_below_5 = is_below_comctl_5();
5904 test_header_notification();
5905 test_header_notification2();
5906 test_images();
5907 test_checkboxes();
5908 test_items();
5909 test_create();
5910 test_redraw();
5911 test_customdraw();
5912 test_icon_spacing();
5913 test_color();
5914 test_item_count();
5915 test_item_position();
5916 test_columns();
5917 test_getorigin();
5918 test_multiselect();
5919 test_getitemrect();
5920 test_subitem_rect();
5921 test_sorting();
5922 test_ownerdata();
5923 test_norecompute();
5924 test_nosortheader();
5925 test_setredraw();
5926 test_hittest();
5927 test_getviewrect();
5928 test_getitemposition();
5929 test_columnscreation();
5930 test_editbox();
5931 test_notifyformat();
5932 test_indentation();
5933 test_getitemspacing();
5934 test_getcolumnwidth();
5935 test_approximate_viewrect();
5936 test_finditem();
5937 test_hover();
5938 test_destroynotify();
5939 test_createdragimage();
5940 test_dispinfo();
5941 test_LVM_SETITEMTEXT();
5942 test_LVM_REDRAWITEMS();
5943 test_imagelists();
5944 test_deleteitem();
5945 test_insertitem();
5946 test_header_proc();
5947 test_oneclickactivate();
5948 test_callback_mask();
5950 if (!load_v6_module(&ctx_cookie, &hCtx))
5952 DestroyWindow(hwndparent);
5953 return;
5956 /* comctl32 version 6 tests start here */
5957 test_get_set_view();
5958 test_canceleditlabel();
5959 test_mapidindex();
5960 test_scrollnotify();
5961 test_LVS_EX_TRANSPARENTBKGND();
5962 test_LVS_EX_HEADERINALLVIEWS();
5963 test_deleteitem();
5964 test_multiselect();
5965 test_insertitem();
5966 test_header_proc();
5968 unload_v6_module(ctx_cookie, hCtx);
5970 DestroyWindow(hwndparent);