include: Use the hard-float calling convention for Windows APIs on ARM
[wine.git] / dlls / comctl32 / tests / listview.c
blob0e12362b6904a7edf2dcad7416227d98c8292be1
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 static const WCHAR testtextW[] = {'t','e','s','t',' ','t','e','x','t',0};
1527 char buff[16];
1528 HWND hList;
1529 HWND hHeader;
1530 LONG_PTR ret;
1531 LONG r;
1532 LVCOLUMNA col;
1533 RECT rect;
1534 WNDCLASSEXA cls;
1535 DWORD style;
1537 cls.cbSize = sizeof(WNDCLASSEXA);
1538 ok(GetClassInfoExA(GetModuleHandleA(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1539 listviewWndProc = cls.lpfnWndProc;
1540 cls.lpfnWndProc = create_test_wndproc;
1541 cls.lpszClassName = "MyListView32";
1542 ok(RegisterClassExA(&cls), "RegisterClassEx failed\n");
1544 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1545 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1546 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1547 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1548 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1549 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1550 DestroyWindow(hList);
1552 /* header isn't created on LVS_ICON and LVS_LIST styles */
1553 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1554 GetModuleHandleA(NULL), 0);
1555 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1556 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1557 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1558 /* insert column */
1559 memset(&col, 0, sizeof(LVCOLUMNA));
1560 col.mask = LVCF_WIDTH;
1561 col.cx = 100;
1562 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1563 expect(0, r);
1564 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1565 ok(IsWindow(hHeader), "Header should be created\n");
1566 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1567 style = GetWindowLongA(hHeader, GWL_STYLE);
1568 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1569 DestroyWindow(hList);
1571 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1572 GetModuleHandleA(NULL), 0);
1573 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1574 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1575 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1576 /* insert column */
1577 memset(&col, 0, sizeof(LVCOLUMNA));
1578 col.mask = LVCF_WIDTH;
1579 col.cx = 100;
1580 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1581 expect(0, r);
1582 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1583 ok(IsWindow(hHeader), "Header should be created\n");
1584 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1585 DestroyWindow(hList);
1587 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1588 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1589 GetModuleHandleA(NULL), 0);
1590 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1591 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1592 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1593 ok(IsWindow(hHeader), "Header should be created\n");
1594 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1595 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1596 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1597 ok(IsWindow(hHeader), "Header should be created\n");
1598 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1599 DestroyWindow(hList);
1601 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1602 hList = CreateWindowA("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1603 GetModuleHandleA(NULL), 0);
1604 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1605 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1606 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1607 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1608 ok(IsWindow(hHeader), "Header should be created\n");
1609 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1610 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1611 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1612 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1613 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1614 ok(IsWindow(hHeader), "Header should be created\n");
1615 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1616 DestroyWindow(hList);
1618 /* LVS_REPORT without WS_VISIBLE */
1619 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1620 GetModuleHandleA(NULL), 0);
1621 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1622 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1623 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1624 /* insert column */
1625 memset(&col, 0, sizeof(LVCOLUMNA));
1626 col.mask = LVCF_WIDTH;
1627 col.cx = 100;
1628 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1629 expect(0, r);
1630 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1631 ok(IsWindow(hHeader), "Header should be created\n");
1632 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1633 DestroyWindow(hList);
1635 /* LVS_REPORT without WS_VISIBLE, try to show it */
1636 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1637 GetModuleHandleA(NULL), 0);
1638 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1639 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1640 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1641 ShowWindow(hList, SW_SHOW);
1642 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1643 ok(IsWindow(hHeader), "Header should be created\n");
1644 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1645 DestroyWindow(hList);
1647 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1648 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1649 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1650 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1651 ok(IsWindow(hHeader), "Header should be created\n");
1652 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1653 /* HDS_DRAGDROP set by default */
1654 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1655 DestroyWindow(hList);
1657 /* setting LVS_EX_HEADERDRAGDROP creates header */
1658 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1659 GetModuleHandleA(NULL), 0);
1660 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1661 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1662 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1663 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1664 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1665 ok(IsWindow(hHeader) ||
1666 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1667 "Header should be created\n");
1668 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1669 DestroyWindow(hList);
1671 /* setting LVS_EX_GRIDLINES creates header */
1672 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1673 GetModuleHandleA(NULL), 0);
1674 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1675 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1676 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1677 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1678 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1679 ok(IsWindow(hHeader) ||
1680 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1681 "Header should be created\n");
1682 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1683 DestroyWindow(hList);
1685 /* setting LVS_EX_FULLROWSELECT creates header */
1686 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1687 GetModuleHandleA(NULL), 0);
1688 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1689 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1690 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1691 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1692 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1693 ok(IsWindow(hHeader) ||
1694 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1695 "Header should be created\n");
1696 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1697 DestroyWindow(hList);
1699 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1700 hList = create_listview_control(LVS_ICON);
1701 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1702 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1703 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1704 DestroyWindow(hList);
1706 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1707 hList = CreateWindowA("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1708 GetModuleHandleA(NULL), 0);
1709 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1710 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1712 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1713 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1714 /* right value contains garbage, probably because header columns are not set up */
1715 expect(0, rect.bottom);
1716 expect(1, r);
1718 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1719 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1720 ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1722 DestroyWindow(hList);
1724 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1725 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1726 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1727 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1728 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1729 DestroyWindow(hList);
1731 /* Test that window text is preserved. */
1732 hList = CreateWindowExA(0, WC_LISTVIEWA, "test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1733 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1734 ok(hList != NULL, "Failed to create ListView window.\n");
1735 *buff = 0;
1736 GetWindowTextA(hList, buff, sizeof(buff));
1737 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1738 DestroyWindow(hList);
1740 hList = CreateWindowExW(0, WC_LISTVIEWW, testtextW, WS_CHILD | WS_BORDER | WS_VISIBLE,
1741 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1742 ok(hList != NULL, "Failed to create ListView window.\n");
1743 *buff = 0;
1744 GetWindowTextA(hList, buff, sizeof(buff));
1745 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1746 DestroyWindow(hList);
1749 static void test_redraw(void)
1751 HWND hwnd;
1752 HDC hdc;
1753 BOOL res;
1754 DWORD r;
1756 hwnd = create_listview_control(LVS_REPORT);
1757 subclass_header(hwnd);
1759 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1761 InvalidateRect(hwnd, NULL, TRUE);
1762 UpdateWindow(hwnd);
1763 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1765 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1767 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1768 /* 1. Without backbuffer */
1769 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1770 expect(TRUE, res);
1772 hdc = GetWindowDC(hwndparent);
1774 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1775 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1776 ok(r == 1, "Expected not zero result\n");
1777 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1778 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1780 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1781 expect(TRUE, res);
1783 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1784 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1785 expect(1, r);
1786 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1787 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1789 /* 2. With backbuffer */
1790 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1791 LVS_EX_DOUBLEBUFFER);
1792 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1793 expect(TRUE, res);
1795 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1796 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1797 expect(1, r);
1798 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1799 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1801 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1802 expect(TRUE, res);
1804 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1805 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1806 todo_wine expect(1, r);
1807 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1808 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1810 ReleaseDC(hwndparent, hdc);
1812 DestroyWindow(hwnd);
1815 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1817 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1819 if(message == WM_NOTIFY) {
1820 NMHDR *nmhdr = (NMHDR*)lParam;
1821 if(nmhdr->code == NM_CUSTOMDRAW) {
1822 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1823 struct message msg;
1825 msg.message = message;
1826 msg.flags = sent|wparam|lparam|custdraw;
1827 msg.wParam = wParam;
1828 msg.lParam = lParam;
1829 msg.id = nmhdr->code;
1830 msg.stage = nmlvcd->nmcd.dwDrawStage;
1831 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1833 switch(nmlvcd->nmcd.dwDrawStage) {
1834 case CDDS_PREPAINT:
1835 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1836 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1837 case CDDS_ITEMPREPAINT:
1838 nmlvcd->clrTextBk = CLR_DEFAULT;
1839 nmlvcd->clrText = RGB(0, 255, 0);
1840 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1841 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1842 clr = GetBkColor(nmlvcd->nmcd.hdc);
1843 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1844 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1845 todo_wine_if(nmlvcd->iSubItem)
1846 ok(clr == c0ffee, "clr=%.8x\n", clr);
1847 return CDRF_NOTIFYPOSTPAINT;
1848 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1849 clr = GetBkColor(nmlvcd->nmcd.hdc);
1850 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1851 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1852 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1853 return CDRF_DODEFAULT;
1855 return CDRF_DODEFAULT;
1859 return DefWindowProcA(hwnd, message, wParam, lParam);
1862 static void test_customdraw(void)
1864 HWND hwnd;
1865 WNDPROC oldwndproc;
1867 hwnd = create_listview_control(LVS_REPORT);
1869 insert_column(hwnd, 0);
1870 insert_column(hwnd, 1);
1871 insert_item(hwnd, 0);
1873 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
1874 (LONG_PTR)cd_wndproc);
1876 InvalidateRect(hwnd, NULL, TRUE);
1877 UpdateWindow(hwnd);
1879 /* message tests */
1880 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1881 InvalidateRect(hwnd, NULL, TRUE);
1882 UpdateWindow(hwnd);
1883 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1885 DestroyWindow(hwnd);
1887 hwnd = create_listview_control(LVS_LIST);
1889 insert_column(hwnd, 0);
1890 insert_column(hwnd, 1);
1891 insert_item(hwnd, 0);
1893 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1894 InvalidateRect(hwnd, NULL, TRUE);
1895 UpdateWindow(hwnd);
1896 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1898 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1899 DestroyWindow(hwnd);
1902 static void test_icon_spacing(void)
1904 /* LVM_SETICONSPACING */
1905 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1907 HWND hwnd;
1908 WORD w, h;
1909 INT r;
1911 hwnd = create_listview_control(LVS_ICON);
1912 ok(hwnd != NULL, "failed to create a listview window\n");
1914 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1915 expect(NFR_ANSI, r);
1917 /* reset the icon spacing to defaults */
1918 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1920 /* now we can request what the defaults are */
1921 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1922 w = LOWORD(r);
1923 h = HIWORD(r);
1925 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1927 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1928 ok(r == MAKELONG(w, h) ||
1929 broken(r == MAKELONG(w, w)), /* win98 */
1930 "Expected %d, got %d\n", MAKELONG(w, h), r);
1932 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1933 expect(MAKELONG(20,30), r);
1935 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1936 expect(MAKELONG(25,35), r);
1938 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1940 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1941 DestroyWindow(hwnd);
1944 static void test_color(void)
1946 RECT rect;
1947 HWND hwnd;
1948 DWORD r;
1949 int i;
1951 COLORREF color;
1952 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1954 hwnd = create_listview_control(LVS_REPORT);
1955 ok(hwnd != NULL, "failed to create a listview window\n");
1957 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1959 for (i = 0; i < 4; i++)
1961 color = colors[i];
1963 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
1964 expect(TRUE, r);
1965 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
1966 expect(color, r);
1968 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
1969 expect (TRUE, r);
1970 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1971 expect(color, r);
1973 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1974 expect(TRUE, r);
1975 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1976 expect(color, r);
1979 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1980 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1982 /* invalidation test done separately to avoid a message chain mess */
1983 r = ValidateRect(hwnd, NULL);
1984 expect(TRUE, r);
1985 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
1986 expect(TRUE, r);
1988 rect.right = rect.bottom = 1;
1989 r = GetUpdateRect(hwnd, &rect, TRUE);
1990 todo_wine expect(FALSE, r);
1991 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1993 r = ValidateRect(hwnd, NULL);
1994 expect(TRUE, r);
1995 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
1996 expect(TRUE, r);
1998 rect.right = rect.bottom = 1;
1999 r = GetUpdateRect(hwnd, &rect, TRUE);
2000 todo_wine expect(FALSE, r);
2001 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2003 r = ValidateRect(hwnd, NULL);
2004 expect(TRUE, r);
2005 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2006 expect(TRUE, r);
2008 rect.right = rect.bottom = 1;
2009 r = GetUpdateRect(hwnd, &rect, TRUE);
2010 todo_wine expect(FALSE, r);
2011 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2013 DestroyWindow(hwnd);
2016 static void test_item_count(void)
2018 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2020 HWND hwnd;
2021 DWORD r;
2022 HDC hdc;
2023 HFONT hOldFont;
2024 TEXTMETRICA tm;
2025 RECT rect;
2026 INT height;
2028 LVITEMA item0;
2029 LVITEMA item1;
2030 LVITEMA item2;
2031 static CHAR item0text[] = "item0";
2032 static CHAR item1text[] = "item1";
2033 static CHAR item2text[] = "item2";
2035 hwnd = create_listview_control(LVS_REPORT);
2036 ok(hwnd != NULL, "failed to create a listview window\n");
2038 /* resize in dpiaware manner to fit all 3 items added */
2039 hdc = GetDC(0);
2040 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2041 GetTextMetricsA(hdc, &tm);
2042 /* 2 extra pixels for bounds and header border */
2043 height = tm.tmHeight + 2;
2044 SelectObject(hdc, hOldFont);
2045 ReleaseDC(0, hdc);
2047 GetWindowRect(hwnd, &rect);
2048 /* 3 items + 1 header + 1 to be sure */
2049 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2051 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2053 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2054 expect(0, r);
2056 /* [item0] */
2057 item0.mask = LVIF_TEXT;
2058 item0.iItem = 0;
2059 item0.iSubItem = 0;
2060 item0.pszText = item0text;
2061 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2062 expect(0, r);
2064 /* [item0, item1] */
2065 item1.mask = LVIF_TEXT;
2066 item1.iItem = 1;
2067 item1.iSubItem = 0;
2068 item1.pszText = item1text;
2069 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2070 expect(1, r);
2072 /* [item0, item1, item2] */
2073 item2.mask = LVIF_TEXT;
2074 item2.iItem = 2;
2075 item2.iSubItem = 0;
2076 item2.pszText = item2text;
2077 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2078 expect(2, r);
2080 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2081 expect(3, r);
2083 /* [item0, item1] */
2084 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2085 expect(TRUE, r);
2087 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2088 expect(2, r);
2090 /* [] */
2091 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2092 expect(TRUE, r);
2094 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2095 expect(0, r);
2097 /* [item0] */
2098 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2099 expect(0, r);
2101 /* [item0, item1] */
2102 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2103 expect(1, r);
2105 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2106 expect(2, r);
2108 /* [item0, item1, item2] */
2109 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2110 expect(2, r);
2112 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2113 expect(3, r);
2115 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2117 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2118 DestroyWindow(hwnd);
2121 static void test_item_position(void)
2123 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2125 HWND hwnd;
2126 DWORD r;
2127 POINT position;
2129 LVITEMA item0;
2130 LVITEMA item1;
2131 LVITEMA item2;
2132 static CHAR item0text[] = "item0";
2133 static CHAR item1text[] = "item1";
2134 static CHAR item2text[] = "item2";
2136 hwnd = create_listview_control(LVS_ICON);
2137 ok(hwnd != NULL, "failed to create a listview window\n");
2139 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2141 /* [item0] */
2142 item0.mask = LVIF_TEXT;
2143 item0.iItem = 0;
2144 item0.iSubItem = 0;
2145 item0.pszText = item0text;
2146 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2147 expect(0, r);
2149 /* [item0, item1] */
2150 item1.mask = LVIF_TEXT;
2151 item1.iItem = 1;
2152 item1.iSubItem = 0;
2153 item1.pszText = item1text;
2154 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2155 expect(1, r);
2157 /* [item0, item1, item2] */
2158 item2.mask = LVIF_TEXT;
2159 item2.iItem = 2;
2160 item2.iSubItem = 0;
2161 item2.pszText = item2text;
2162 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2163 expect(2, r);
2165 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2166 expect(TRUE, r);
2167 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2168 expect(TRUE, r);
2169 expect2(10, 5, position.x, position.y);
2171 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2172 expect(TRUE, r);
2173 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2174 expect(TRUE, r);
2175 expect2(0, 0, position.x, position.y);
2177 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2178 expect(TRUE, r);
2179 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2180 expect(TRUE, r);
2181 expect2(20, 20, position.x, position.y);
2183 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2185 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2186 DestroyWindow(hwnd);
2189 static void test_getorigin(void)
2191 /* LVM_GETORIGIN */
2193 HWND hwnd;
2194 DWORD r;
2195 POINT position;
2197 position.x = position.y = 0;
2199 hwnd = create_listview_control(LVS_ICON);
2200 ok(hwnd != NULL, "failed to create a listview window\n");
2201 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2203 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2204 expect(TRUE, r);
2205 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2206 DestroyWindow(hwnd);
2208 hwnd = create_listview_control(LVS_SMALLICON);
2209 ok(hwnd != NULL, "failed to create a listview window\n");
2210 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2212 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2213 expect(TRUE, r);
2214 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2215 DestroyWindow(hwnd);
2217 hwnd = create_listview_control(LVS_LIST);
2218 ok(hwnd != NULL, "failed to create a listview window\n");
2219 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2221 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2222 expect(FALSE, r);
2223 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2224 DestroyWindow(hwnd);
2226 hwnd = create_listview_control(LVS_REPORT);
2227 ok(hwnd != NULL, "failed to create a listview window\n");
2228 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2230 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2231 expect(FALSE, r);
2232 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2233 DestroyWindow(hwnd);
2236 static void test_multiselect(void)
2238 typedef struct t_select_task
2240 const char *descr;
2241 int initPos;
2242 int loopVK;
2243 int count;
2244 int result;
2245 } select_task;
2247 HWND hwnd;
2248 INT r;
2249 int i, j;
2250 static const int items=5;
2251 DWORD item_count;
2252 BYTE kstate[256];
2253 select_task task;
2254 LONG_PTR style;
2255 LVITEMA item;
2257 static struct t_select_task task_list[] = {
2258 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2259 { "using VK_UP", -1, VK_UP, -1, -1 },
2260 { "using VK_END", 0, VK_END, 1, -1 },
2261 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2264 hwnd = create_listview_control(LVS_REPORT);
2266 for (i = 0; i < items; i++)
2267 insert_item(hwnd, 0);
2269 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2270 expect(items, item_count);
2272 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2273 ok(r == -1, "got %d\n", r);
2275 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2276 ok(r == -1, "got %d\n", r);
2278 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2279 ok(r == 0, "got %d\n", r);
2281 /* out of range index */
2282 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, items);
2283 ok(r == 0, "got %d\n", r);
2285 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2286 ok(r == 0, "got %d\n", r);
2288 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -2);
2289 ok(r == 0, "got %d\n", r);
2291 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2292 ok(r == 0, "got %d\n", r);
2294 for (i = 0; i < sizeof(task_list)/sizeof(task_list[0]); i++) {
2295 DWORD selected_count;
2296 LVITEMA item;
2298 task = task_list[i];
2300 /* deselect all items */
2301 item.state = 0;
2302 item.stateMask = LVIS_SELECTED;
2303 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2304 ok(r, "got %d\n", r);
2305 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2307 /* set initial position */
2308 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2309 ok(r, "got %d\n", r);
2311 item.state = LVIS_SELECTED;
2312 item.stateMask = LVIS_SELECTED;
2313 r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2314 ok(r, "got %d\n", r);
2316 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2317 ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2319 /* Set SHIFT key pressed */
2320 GetKeyboardState(kstate);
2321 kstate[VK_SHIFT]=0x80;
2322 SetKeyboardState(kstate);
2324 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2325 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2326 expect(0,r);
2327 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2328 expect(0,r);
2331 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2333 ok((task.result == -1 ? item_count : task.result) == selected_count,
2334 "Failed multiple selection %s. There should be %d selected items (is %d)\n",
2335 task.descr, item_count, selected_count);
2337 /* Set SHIFT key released */
2338 GetKeyboardState(kstate);
2339 kstate[VK_SHIFT]=0x00;
2340 SetKeyboardState(kstate);
2342 DestroyWindow(hwnd);
2344 /* make multiple selection, then switch to LVS_SINGLESEL */
2345 hwnd = create_listview_control(LVS_REPORT);
2346 for (i=0;i<items;i++) {
2347 insert_item(hwnd, 0);
2349 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2350 expect(items,item_count);
2352 /* try with NULL pointer */
2353 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2354 expect(FALSE, r);
2356 /* select all, check notifications */
2357 item.state = 0;
2358 item.stateMask = LVIS_SELECTED;
2359 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2360 ok(r, "got %d\n", r);
2362 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2364 item.stateMask = LVIS_SELECTED;
2365 item.state = LVIS_SELECTED;
2366 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2367 expect(TRUE, r);
2369 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2370 "select all notification", FALSE);
2372 /* select all again (all selected already) */
2373 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2375 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2377 item.stateMask = LVIS_SELECTED;
2378 item.state = LVIS_SELECTED;
2379 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2380 expect(TRUE, r);
2382 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2383 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2384 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2386 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2387 "select all notification 2", FALSE);
2389 /* deselect all items */
2390 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2392 item.state = 0;
2393 item.stateMask = LVIS_SELECTED;
2394 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2395 ok(r, "got %d\n", r);
2397 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2398 "deselect all notification", FALSE);
2400 /* deselect all items again */
2401 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2402 item.state = 0;
2403 item.stateMask = LVIS_SELECTED;
2404 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2405 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2407 /* any non-zero state value does the same */
2408 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2410 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2412 item.stateMask = LVIS_SELECTED;
2413 item.state = LVIS_CUT;
2414 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2415 expect(TRUE, r);
2417 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2418 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2419 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2421 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2422 "set state all notification 3", FALSE);
2424 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2425 ok(r, "got %d\n", r);
2426 for (i = 0; i < 3; i++) {
2427 item.state = LVIS_SELECTED;
2428 item.stateMask = LVIS_SELECTED;
2429 r = SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2430 ok(r, "got %d\n", r);
2433 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2434 expect(3, r);
2435 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2436 expect(-1, r);
2438 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2439 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2440 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2441 /* check that style is accepted */
2442 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2443 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2445 for (i=0;i<3;i++) {
2446 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2447 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2449 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2450 expect(3, r);
2451 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2452 ok(r == -1, "got %d\n", r);
2454 /* select one more */
2455 item.state = LVIS_SELECTED;
2456 item.stateMask = LVIS_SELECTED;
2457 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2458 ok(r, "got %d\n", r);
2460 for (i=0;i<3;i++) {
2461 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2462 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2465 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2466 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2468 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2469 expect(1, r);
2470 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2471 expect(-1, r);
2473 /* try to select all on LVS_SINGLESEL */
2474 memset(&item, 0, sizeof(item));
2475 item.stateMask = LVIS_SELECTED;
2476 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2477 expect(TRUE, r);
2478 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2479 ok(r == -1, "got %d\n", r);
2481 item.stateMask = LVIS_SELECTED;
2482 item.state = LVIS_SELECTED;
2483 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2484 expect(FALSE, r);
2486 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2487 expect(0, r);
2488 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2489 expect(-1, r);
2491 /* try to deselect all on LVS_SINGLESEL */
2492 item.stateMask = LVIS_SELECTED;
2493 item.state = LVIS_SELECTED;
2494 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2495 expect(TRUE, r);
2497 item.stateMask = LVIS_SELECTED;
2498 item.state = 0;
2499 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2500 expect(TRUE, r);
2501 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2502 expect(0, r);
2504 /* 1. selection mark is update when new focused item is set */
2505 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2506 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2508 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2509 expect(-1, r);
2511 item.stateMask = LVIS_FOCUSED;
2512 item.state = LVIS_FOCUSED;
2513 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2514 expect(TRUE, r);
2516 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2517 expect(0, r);
2519 /* it's not updated if already set */
2520 item.stateMask = LVIS_FOCUSED;
2521 item.state = LVIS_FOCUSED;
2522 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2523 expect(TRUE, r);
2525 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2526 expect(0, r);
2528 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2529 expect(0, r);
2531 item.stateMask = LVIS_FOCUSED;
2532 item.state = LVIS_FOCUSED;
2533 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2534 expect(TRUE, r);
2536 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2537 expect(-1, r);
2539 /* need to reset focused item first */
2540 item.stateMask = LVIS_FOCUSED;
2541 item.state = 0;
2542 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2543 expect(TRUE, r);
2545 item.stateMask = LVIS_FOCUSED;
2546 item.state = LVIS_FOCUSED;
2547 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2548 expect(TRUE, r);
2550 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2551 expect(2, r);
2553 item.stateMask = LVIS_FOCUSED;
2554 item.state = 0;
2555 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2556 expect(TRUE, r);
2558 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2559 expect(2, r);
2561 /* 2. same tests, with LVM_SETITEM */
2562 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2563 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2565 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2566 expect(2, r);
2568 item.stateMask = LVIS_FOCUSED;
2569 item.state = LVIS_FOCUSED;
2570 item.mask = LVIF_STATE;
2571 item.iItem = item.iSubItem = 0;
2572 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2573 expect(TRUE, r);
2575 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2576 expect(0, r);
2578 /* it's not updated if already set */
2579 item.stateMask = LVIS_FOCUSED;
2580 item.state = LVIS_FOCUSED;
2581 item.mask = LVIF_STATE;
2582 item.iItem = 1;
2583 item.iSubItem = 0;
2584 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2585 expect(TRUE, r);
2587 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2588 expect(0, r);
2590 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2591 expect(0, r);
2593 item.stateMask = LVIS_FOCUSED;
2594 item.state = LVIS_FOCUSED;
2595 item.mask = LVIF_STATE;
2596 item.iItem = 1;
2597 item.iSubItem = 0;
2598 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2599 expect(TRUE, r);
2601 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2602 expect(-1, r);
2604 /* need to reset focused item first */
2605 item.stateMask = LVIS_FOCUSED;
2606 item.state = 0;
2607 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2608 expect(TRUE, r);
2610 item.stateMask = LVIS_FOCUSED;
2611 item.state = LVIS_FOCUSED;
2612 item.mask = LVIF_STATE;
2613 item.iItem = 2;
2614 item.iSubItem = 0;
2615 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2616 expect(TRUE, r);
2618 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2619 expect(2, r);
2621 item.stateMask = LVIS_FOCUSED;
2622 item.state = 0;
2623 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2624 expect(TRUE, r);
2626 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2627 expect(2, r);
2629 DestroyWindow(hwnd);
2632 static void test_subitem_rect(void)
2634 HWND hwnd;
2635 DWORD r;
2636 LVCOLUMNA col;
2637 RECT rect, rect2;
2638 INT arr[3];
2640 /* test LVM_GETSUBITEMRECT for header */
2641 hwnd = create_listview_control(LVS_REPORT);
2642 ok(hwnd != NULL, "failed to create a listview window\n");
2643 /* add some columns */
2644 memset(&col, 0, sizeof(LVCOLUMNA));
2645 col.mask = LVCF_WIDTH;
2646 col.cx = 100;
2647 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2648 expect(0, r);
2649 col.cx = 150;
2650 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2651 expect(1, r);
2652 col.cx = 200;
2653 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2654 expect(2, r);
2655 /* item = -1 means header, subitem index is 1 based */
2656 SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2657 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2658 expect(0, r);
2660 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2661 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2662 expect(1, r);
2664 expect(100, rect.left);
2665 expect(250, rect.right);
2666 expect(3, rect.top);
2668 SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2669 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2670 expect(1, r);
2672 expect(250, rect.left);
2673 expect(450, rect.right);
2674 expect(3, rect.top);
2676 /* item LVS_REPORT padding isn't applied to subitems */
2677 insert_item(hwnd, 0);
2679 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2680 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2681 expect(1, r);
2682 expect(100, rect.left);
2683 expect(250, rect.right);
2685 SetRect(&rect, LVIR_ICON, 1, 0, 0);
2686 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2687 expect(1, r);
2688 /* no icon attached - zero width rectangle, with no left padding */
2689 expect(100, rect.left);
2690 expect(100, rect.right);
2692 SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2693 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2694 expect(1, r);
2695 /* same as full LVIR_BOUNDS */
2696 expect(100, rect.left);
2697 expect(250, rect.right);
2699 r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2700 ok(r, "got %d\n", r);
2702 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2703 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2704 expect(1, r);
2705 expect(90, rect.left);
2706 expect(240, rect.right);
2708 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2710 /* test header interaction */
2711 subclass_header(hwnd);
2712 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2714 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2715 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2716 expect(1, r);
2718 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2719 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2720 expect(1, r);
2722 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2723 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2724 expect(1, r);
2726 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2727 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2728 expect(1, r);
2730 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2732 DestroyWindow(hwnd);
2734 /* test subitem rects after re-arranging columns */
2735 hwnd = create_listview_control(LVS_REPORT);
2736 ok(hwnd != NULL, "failed to create a listview window\n");
2737 memset(&col, 0, sizeof(LVCOLUMNA));
2738 col.mask = LVCF_WIDTH;
2740 col.cx = 100;
2741 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2742 expect(0, r);
2744 col.cx = 200;
2745 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2746 expect(1, r);
2748 col.cx = 300;
2749 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2750 expect(2, r);
2752 insert_item(hwnd, 0);
2753 insert_item(hwnd, 1);
2755 /* wrong item is refused for main item */
2756 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2757 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2758 expect(FALSE, r);
2760 /* for subitems rectangle is calculated even if there's no item added */
2761 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2762 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2763 expect(TRUE, r);
2765 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2766 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2767 expect(TRUE, r);
2768 expect(rect.right, rect2.right);
2769 expect(rect.left, rect2.left);
2770 expect(rect.bottom, rect2.top);
2771 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2773 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2774 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2775 expect(TRUE, r);
2777 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2778 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2779 expect(TRUE, r);
2780 expect(0, rect.left);
2781 expect(600, rect.right);
2783 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2784 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2785 expect(TRUE, r);
2786 expect(0, rect.left);
2787 expect(200, rect.right);
2789 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2790 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2791 expect(TRUE, r);
2792 expect(0, rect2.left);
2793 expect(200, rect2.right);
2794 /* items are of the same height */
2795 ok(rect2.top > 0, "expected positive item height\n");
2796 expect(rect.bottom, rect2.top);
2797 expect(rect.bottom * 2 - rect.top, rect2.bottom);
2799 SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
2800 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2801 expect(TRUE, r);
2802 expect(300, rect.left);
2803 expect(600, rect.right);
2805 DestroyWindow(hwnd);
2807 /* try it for non LVS_REPORT style */
2808 hwnd = CreateWindowA("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2809 GetModuleHandleA(NULL), 0);
2810 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
2811 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2812 expect(0, r);
2813 /* rect is unchanged */
2814 expect(0, rect.left);
2815 expect(-10, rect.right);
2816 expect(1, rect.top);
2817 expect(-10, rect.bottom);
2818 DestroyWindow(hwnd);
2821 /* comparison callback for test_sorting */
2822 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2824 if (first == second) return 0;
2825 return (first > second ? 1 : -1);
2828 static void test_sorting(void)
2830 HWND hwnd;
2831 LVITEMA item = {0};
2832 INT r;
2833 LONG_PTR style;
2834 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2835 CHAR buff[10];
2837 hwnd = create_listview_control(LVS_REPORT);
2838 ok(hwnd != NULL, "failed to create a listview window\n");
2840 /* insert some items */
2841 item.mask = LVIF_PARAM | LVIF_STATE;
2842 item.state = LVIS_SELECTED;
2843 item.iItem = 0;
2844 item.iSubItem = 0;
2845 item.lParam = 3;
2846 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2847 expect(0, r);
2849 item.mask = LVIF_PARAM;
2850 item.iItem = 1;
2851 item.iSubItem = 0;
2852 item.lParam = 2;
2853 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2854 expect(1, r);
2856 item.mask = LVIF_STATE | LVIF_PARAM;
2857 item.state = LVIS_SELECTED;
2858 item.iItem = 2;
2859 item.iSubItem = 0;
2860 item.lParam = 4;
2861 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2862 expect(2, r);
2864 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2865 expect(-1, r);
2867 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2868 expect(2, r);
2870 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2871 expect(TRUE, r);
2873 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2874 expect(2, r);
2875 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2876 expect(-1, r);
2877 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2878 expect(0, r);
2879 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2880 expect(LVIS_SELECTED, r);
2881 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2882 expect(LVIS_SELECTED, r);
2884 DestroyWindow(hwnd);
2886 /* switch to LVS_SORTASCENDING when some items added */
2887 hwnd = create_listview_control(LVS_REPORT);
2888 ok(hwnd != NULL, "failed to create a listview window\n");
2890 item.mask = LVIF_TEXT;
2891 item.iItem = 0;
2892 item.iSubItem = 0;
2893 item.pszText = names[1];
2894 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2895 expect(0, r);
2897 item.mask = LVIF_TEXT;
2898 item.iItem = 1;
2899 item.iSubItem = 0;
2900 item.pszText = names[2];
2901 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2902 expect(1, r);
2904 item.mask = LVIF_TEXT;
2905 item.iItem = 2;
2906 item.iSubItem = 0;
2907 item.pszText = names[0];
2908 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2909 expect(2, r);
2911 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2912 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2913 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2914 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2916 /* no sorting performed when switched to LVS_SORTASCENDING */
2917 item.mask = LVIF_TEXT;
2918 item.iItem = 0;
2919 item.pszText = buff;
2920 item.cchTextMax = sizeof(buff);
2921 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2922 expect(TRUE, r);
2923 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2925 item.iItem = 1;
2926 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2927 expect(TRUE, r);
2928 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2930 item.iItem = 2;
2931 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2932 expect(TRUE, r);
2933 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2935 /* adding new item doesn't resort list */
2936 item.mask = LVIF_TEXT;
2937 item.iItem = 3;
2938 item.iSubItem = 0;
2939 item.pszText = names[3];
2940 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2941 expect(3, r);
2943 item.mask = LVIF_TEXT;
2944 item.iItem = 0;
2945 item.pszText = buff;
2946 item.cchTextMax = sizeof(buff);
2947 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2948 expect(TRUE, r);
2949 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2951 item.iItem = 1;
2952 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2953 expect(TRUE, r);
2954 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2956 item.iItem = 2;
2957 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2958 expect(TRUE, r);
2959 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2961 item.iItem = 3;
2962 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2963 expect(TRUE, r);
2964 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2966 /* corner case - item should be placed at first position */
2967 item.mask = LVIF_TEXT;
2968 item.iItem = 4;
2969 item.iSubItem = 0;
2970 item.pszText = names[4];
2971 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
2972 expect(0, r);
2974 item.iItem = 0;
2975 item.pszText = buff;
2976 item.cchTextMax = sizeof(buff);
2977 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2978 expect(TRUE, r);
2979 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2981 item.iItem = 1;
2982 item.pszText = buff;
2983 item.cchTextMax = sizeof(buff);
2984 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2985 expect(TRUE, r);
2986 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2988 item.iItem = 2;
2989 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2990 expect(TRUE, r);
2991 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2993 item.iItem = 3;
2994 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
2995 expect(TRUE, r);
2996 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2998 item.iItem = 4;
2999 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3000 expect(TRUE, r);
3001 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3003 DestroyWindow(hwnd);
3006 static void test_ownerdata(void)
3008 static char test_str[] = "test";
3010 HWND hwnd;
3011 LONG_PTR style, ret;
3012 DWORD res;
3013 LVITEMA item;
3015 /* it isn't possible to set LVS_OWNERDATA after creation */
3016 if (g_is_below_5)
3018 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3020 else
3022 hwnd = create_listview_control(LVS_REPORT);
3023 ok(hwnd != NULL, "failed to create a listview window\n");
3024 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3025 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3027 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3029 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3030 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3031 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3032 "try to switch to LVS_OWNERDATA seq", FALSE);
3034 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3035 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3036 DestroyWindow(hwnd);
3039 /* try to set LVS_OWNERDATA after creation just having it */
3040 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3041 ok(hwnd != NULL, "failed to create a listview window\n");
3042 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3043 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3045 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3047 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3048 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3049 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3050 "try to switch to LVS_OWNERDATA seq", FALSE);
3051 DestroyWindow(hwnd);
3053 /* try to remove LVS_OWNERDATA after creation just having it */
3054 if (g_is_below_5)
3056 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3058 else
3060 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3061 ok(hwnd != NULL, "failed to create a listview window\n");
3062 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3063 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3065 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3067 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3068 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3069 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3070 "try to switch to LVS_OWNERDATA seq", FALSE);
3071 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3072 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3073 DestroyWindow(hwnd);
3076 /* try select an item */
3077 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3078 ok(hwnd != NULL, "failed to create a listview window\n");
3079 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3080 expect(1, res);
3081 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3082 expect(0, res);
3083 memset(&item, 0, sizeof(item));
3084 item.stateMask = LVIS_SELECTED;
3085 item.state = LVIS_SELECTED;
3086 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3087 expect(TRUE, res);
3088 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3089 expect(1, res);
3090 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3091 expect(1, res);
3092 DestroyWindow(hwnd);
3094 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3095 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3096 ok(hwnd != NULL, "failed to create a listview window\n");
3097 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3098 expect(1, res);
3099 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3100 expect(1, res);
3101 memset(&item, 0, sizeof(item));
3102 item.mask = LVIF_STATE;
3103 item.iItem = 0;
3104 item.stateMask = LVIS_SELECTED;
3105 item.state = LVIS_SELECTED;
3106 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3107 expect(FALSE, res);
3108 memset(&item, 0, sizeof(item));
3109 item.pszText = test_str;
3110 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3111 expect(FALSE, res);
3112 DestroyWindow(hwnd);
3114 /* check notifications after focused/selected changed */
3115 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3116 ok(hwnd != NULL, "failed to create a listview window\n");
3117 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3118 expect(1, res);
3120 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3122 memset(&item, 0, sizeof(item));
3123 item.stateMask = LVIS_SELECTED;
3124 item.state = LVIS_SELECTED;
3125 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3126 expect(TRUE, res);
3128 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3129 "ownerdata select notification", TRUE);
3131 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3133 memset(&item, 0, sizeof(item));
3134 item.stateMask = LVIS_FOCUSED;
3135 item.state = LVIS_FOCUSED;
3136 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3137 expect(TRUE, res);
3139 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3140 "ownerdata focus notification", TRUE);
3142 /* select all, check notifications */
3143 item.stateMask = LVIS_SELECTED;
3144 item.state = 0;
3145 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3146 expect(TRUE, res);
3148 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3150 item.stateMask = LVIS_SELECTED;
3151 item.state = LVIS_SELECTED;
3153 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3154 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3155 expect(TRUE, res);
3156 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3157 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3158 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3159 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3160 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3161 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3162 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3164 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3165 "ownerdata select all notification", FALSE);
3167 /* select all again, note that all items are selected already */
3168 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3169 item.stateMask = LVIS_SELECTED;
3170 item.state = LVIS_SELECTED;
3172 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3173 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3174 expect(TRUE, res);
3175 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3176 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3177 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3178 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3179 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3180 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3181 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3183 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3184 "ownerdata select all notification", FALSE);
3186 /* deselect all */
3187 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3188 item.stateMask = LVIS_SELECTED;
3189 item.state = 0;
3191 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3192 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3193 expect(TRUE, res);
3194 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3195 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3196 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3197 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3198 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3199 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3200 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3202 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3203 "ownerdata deselect all notification", TRUE);
3205 /* nothing selected, deselect all again */
3206 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3207 item.stateMask = LVIS_SELECTED;
3208 item.state = 0;
3210 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3211 expect(TRUE, res);
3213 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3215 /* select one, then deselect all */
3216 item.stateMask = LVIS_SELECTED;
3217 item.state = LVIS_SELECTED;
3218 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3219 expect(TRUE, res);
3220 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3221 item.stateMask = LVIS_SELECTED;
3222 item.state = 0;
3224 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3225 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3226 expect(TRUE, res);
3227 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3228 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3229 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3230 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3231 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3232 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3233 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3235 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3236 "ownerdata select all notification", TRUE);
3238 /* remove focused, try to focus all */
3239 item.stateMask = LVIS_FOCUSED;
3240 item.state = LVIS_FOCUSED;
3241 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3242 expect(TRUE, res);
3243 item.stateMask = LVIS_FOCUSED;
3244 item.state = 0;
3245 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3246 expect(TRUE, res);
3247 item.stateMask = LVIS_FOCUSED;
3248 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3249 expect(0, res);
3251 /* setting all to focused returns failure value */
3252 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3253 item.stateMask = LVIS_FOCUSED;
3254 item.state = LVIS_FOCUSED;
3256 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3257 expect(FALSE, res);
3259 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3260 "ownerdata focus all notification", FALSE);
3262 /* focus single item, remove all */
3263 item.stateMask = LVIS_FOCUSED;
3264 item.state = LVIS_FOCUSED;
3265 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3266 expect(TRUE, res);
3267 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3268 item.stateMask = LVIS_FOCUSED;
3269 item.state = 0;
3271 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3272 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3273 expect(TRUE, res);
3274 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3275 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3276 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3277 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3278 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3279 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3280 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3282 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3283 "ownerdata remove focus all notification", TRUE);
3285 /* set all cut */
3286 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3287 item.stateMask = LVIS_CUT;
3288 item.state = LVIS_CUT;
3290 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3291 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3292 expect(TRUE, res);
3293 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3294 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3295 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3296 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3297 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3298 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3299 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3301 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3302 "ownerdata cut all notification", FALSE);
3304 /* all marked cut, try again */
3305 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3306 item.stateMask = LVIS_CUT;
3307 item.state = LVIS_CUT;
3309 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3310 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3311 expect(TRUE, res);
3312 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3313 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3314 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3315 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3316 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3317 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3318 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3320 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3321 "ownerdata cut all notification #2", FALSE);
3323 DestroyWindow(hwnd);
3325 /* check notifications on LVM_GETITEM */
3326 /* zero callback mask */
3327 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3328 ok(hwnd != NULL, "failed to create a listview window\n");
3329 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3330 expect(1, res);
3332 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3334 memset(&item, 0, sizeof(item));
3335 item.stateMask = LVIS_SELECTED;
3336 item.mask = LVIF_STATE;
3337 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3338 expect(TRUE, res);
3340 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3341 "ownerdata getitem selected state 1", FALSE);
3343 /* non zero callback mask but not we asking for */
3344 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3345 expect(TRUE, res);
3347 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3349 memset(&item, 0, sizeof(item));
3350 item.stateMask = LVIS_SELECTED;
3351 item.mask = LVIF_STATE;
3352 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3353 expect(TRUE, res);
3355 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3356 "ownerdata getitem selected state 2", FALSE);
3358 /* LVIS_OVERLAYMASK callback mask, asking for index */
3359 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3361 memset(&item, 0, sizeof(item));
3362 item.stateMask = LVIS_OVERLAYMASK;
3363 item.mask = LVIF_STATE;
3364 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3365 expect(TRUE, res);
3367 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3368 "ownerdata getitem selected state 2", FALSE);
3370 DestroyWindow(hwnd);
3372 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3373 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3374 ok(hwnd != NULL, "failed to create a listview window\n");
3375 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3376 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3377 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3378 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3379 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3380 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3381 DestroyWindow(hwnd);
3382 /* apparently it's allowed to switch these style on after creation */
3383 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3384 ok(hwnd != NULL, "failed to create a listview window\n");
3385 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3386 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3387 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3388 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3389 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3390 DestroyWindow(hwnd);
3392 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3393 ok(hwnd != NULL, "failed to create a listview window\n");
3394 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3395 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3396 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3397 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3398 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3399 DestroyWindow(hwnd);
3401 /* The focused item is updated after the invalidation */
3402 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3403 ok(hwnd != NULL, "failed to create a listview window\n");
3404 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3405 expect(TRUE, res);
3407 memset(&item, 0, sizeof(item));
3408 item.stateMask = LVIS_FOCUSED;
3409 item.state = LVIS_FOCUSED;
3410 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3411 expect(TRUE, res);
3413 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3414 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3415 expect(TRUE, res);
3416 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3417 "ownerdata setitemcount", FALSE);
3419 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3420 expect(-1, res);
3421 DestroyWindow(hwnd);
3424 static void test_norecompute(void)
3426 static CHAR testA[] = "test";
3427 CHAR buff[10];
3428 LVITEMA item;
3429 HWND hwnd;
3430 DWORD res;
3432 /* self containing control */
3433 hwnd = create_listview_control(LVS_REPORT);
3434 ok(hwnd != NULL, "failed to create a listview window\n");
3435 memset(&item, 0, sizeof(item));
3436 item.mask = LVIF_TEXT | LVIF_STATE;
3437 item.iItem = 0;
3438 item.stateMask = LVIS_SELECTED;
3439 item.state = LVIS_SELECTED;
3440 item.pszText = testA;
3441 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3442 expect(0, res);
3443 /* retrieve with LVIF_NORECOMPUTE */
3444 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3445 item.iItem = 0;
3446 item.pszText = buff;
3447 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3448 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3449 expect(TRUE, res);
3450 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3452 item.mask = LVIF_TEXT;
3453 item.iItem = 1;
3454 item.pszText = LPSTR_TEXTCALLBACKA;
3455 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3456 expect(1, res);
3458 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3459 item.iItem = 1;
3460 item.pszText = buff;
3461 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3463 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3464 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3465 expect(TRUE, res);
3466 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3467 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3468 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3470 DestroyWindow(hwnd);
3472 /* LVS_OWNERDATA */
3473 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3474 ok(hwnd != NULL, "failed to create a listview window\n");
3476 item.mask = LVIF_STATE;
3477 item.stateMask = LVIS_SELECTED;
3478 item.state = LVIS_SELECTED;
3479 item.iItem = 0;
3480 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3481 expect(0, res);
3483 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3484 item.iItem = 0;
3485 item.pszText = buff;
3486 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3487 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3488 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3489 expect(TRUE, res);
3490 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3491 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3492 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3494 DestroyWindow(hwnd);
3497 static void test_nosortheader(void)
3499 HWND hwnd, header;
3500 LONG_PTR style;
3502 hwnd = create_listview_control(LVS_REPORT);
3503 ok(hwnd != NULL, "failed to create a listview window\n");
3505 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3506 ok(IsWindow(header), "header expected\n");
3508 style = GetWindowLongPtrA(header, GWL_STYLE);
3509 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3511 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3512 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3513 /* HDS_BUTTONS retained */
3514 style = GetWindowLongPtrA(header, GWL_STYLE);
3515 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3517 DestroyWindow(hwnd);
3519 /* create with LVS_NOSORTHEADER */
3520 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3521 ok(hwnd != NULL, "failed to create a listview window\n");
3523 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3524 ok(IsWindow(header), "header expected\n");
3526 style = GetWindowLongPtrA(header, GWL_STYLE);
3527 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3529 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3530 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3531 /* not changed here */
3532 style = GetWindowLongPtrA(header, GWL_STYLE);
3533 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3535 DestroyWindow(hwnd);
3538 static void test_setredraw(void)
3540 HWND hwnd;
3541 DWORD_PTR style;
3542 DWORD ret;
3543 HDC hdc;
3544 RECT rect;
3546 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3547 ok(hwnd != NULL, "failed to create a listview window\n");
3549 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3550 ListView seems to handle it internally without DefWinProc */
3552 /* default value first */
3553 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3554 expect(0, ret);
3555 /* disable */
3556 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3557 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3558 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3559 expect(0, ret);
3560 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3561 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3562 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3563 expect(0, ret);
3565 /* check update rect after redrawing */
3566 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3567 expect(0, ret);
3568 InvalidateRect(hwnd, NULL, FALSE);
3569 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3570 rect.right = rect.bottom = 1;
3571 GetUpdateRect(hwnd, &rect, FALSE);
3572 expect(0, rect.right);
3573 expect(0, rect.bottom);
3575 /* WM_ERASEBKGND */
3576 hdc = GetWindowDC(hwndparent);
3577 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3578 expect(TRUE, ret);
3579 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3580 expect(0, ret);
3581 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3582 expect(TRUE, ret);
3583 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3584 expect(0, ret);
3585 ReleaseDC(hwndparent, hdc);
3587 /* check notification messages to show that repainting is disabled */
3588 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3589 expect(TRUE, ret);
3590 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3591 expect(0, ret);
3592 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3594 InvalidateRect(hwnd, NULL, TRUE);
3595 UpdateWindow(hwnd);
3596 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3597 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3599 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3600 expect(TRUE, ret);
3601 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3602 InvalidateRect(hwnd, NULL, TRUE);
3603 UpdateWindow(hwnd);
3604 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3605 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3607 /* message isn't forwarded to header */
3608 subclass_header(hwnd);
3609 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3610 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3611 expect(0, ret);
3612 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3613 "WM_SETREDRAW: not forwarded to header", FALSE);
3615 DestroyWindow(hwnd);
3618 static void test_hittest(void)
3620 HWND hwnd;
3621 DWORD r;
3622 RECT bounds;
3623 LVITEMA item;
3624 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3625 POINT pos;
3626 INT x, y, i;
3627 WORD vert;
3628 HIMAGELIST himl, himl2;
3629 HBITMAP hbmp;
3631 hwnd = create_listview_control(LVS_REPORT);
3632 ok(hwnd != NULL, "failed to create a listview window\n");
3634 /* LVS_REPORT with a single subitem (2 columns) */
3635 insert_column(hwnd, 0);
3636 insert_column(hwnd, 1);
3637 insert_item(hwnd, 0);
3639 item.iSubItem = 0;
3640 /* the only purpose of that line is to be as long as a half item rect */
3641 item.pszText = text;
3642 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3643 expect(TRUE, r);
3645 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3646 expect(TRUE, r);
3647 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3648 expect(TRUE, r);
3650 SetRect(&bounds, LVIR_BOUNDS, 0, 0, 0);
3651 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3652 expect(1, r);
3653 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3654 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3655 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3656 vert = HIWORD(r);
3657 ok(bounds.bottom - bounds.top == vert,
3658 "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3659 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3660 expect(TRUE, r);
3662 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3664 /* outside columns by x position - valid is [0, 199] */
3665 x = -1;
3666 y = pos.y + (bounds.bottom - bounds.top) / 2;
3667 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3668 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3670 x = pos.x + 50; /* column half width */
3671 y = pos.y + (bounds.bottom - bounds.top) / 2;
3672 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3673 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3674 x = pos.x + 150; /* outside column */
3675 y = pos.y + (bounds.bottom - bounds.top) / 2;
3676 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3677 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3678 y = (bounds.bottom - bounds.top) / 2;
3679 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3680 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3681 /* outside possible client rectangle (to right) */
3682 x = pos.x + 500;
3683 y = pos.y + (bounds.bottom - bounds.top) / 2;
3684 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3685 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3686 y = (bounds.bottom - bounds.top) / 2;
3687 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3688 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3689 /* subitem returned with -1 item too */
3690 x = pos.x + 150;
3691 y = bounds.top - vert;
3692 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3693 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3694 /* return values appear to underflow with negative indices */
3695 i = -2;
3696 y = y - vert;
3697 while (i > -10) {
3698 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3699 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3700 y = y - vert;
3701 i--;
3703 /* parent client area is 100x100 by default */
3704 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3705 x = pos.x + 150; /* outside column */
3706 y = pos.y + (bounds.bottom - bounds.top) / 2;
3707 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3708 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3709 y = (bounds.bottom - bounds.top) / 2;
3710 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3711 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3712 /* the same with LVS_EX_FULLROWSELECT */
3713 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3714 x = pos.x + 150; /* outside column */
3715 y = pos.y + (bounds.bottom - bounds.top) / 2;
3716 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3717 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3718 y = (bounds.bottom - bounds.top) / 2;
3719 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3720 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3721 x = pos.x + 150; /* outside column */
3722 y = pos.y + (bounds.bottom - bounds.top) / 2;
3723 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3724 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3725 y = (bounds.bottom - bounds.top) / 2;
3726 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3727 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3728 /* outside possible client rectangle (to right) */
3729 x = pos.x + 500;
3730 y = pos.y + (bounds.bottom - bounds.top) / 2;
3731 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3732 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3733 y = (bounds.bottom - bounds.top) / 2;
3734 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3735 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3736 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3737 himl = ImageList_Create(16, 16, 0, 4, 4);
3738 ok(himl != NULL, "failed to create imagelist\n");
3739 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3740 ok(hbmp != NULL, "failed to create bitmap\n");
3741 r = ImageList_Add(himl, hbmp, 0);
3742 ok(r == 0, "should be zero\n");
3743 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3744 ok(hbmp != NULL, "failed to create bitmap\n");
3745 r = ImageList_Add(himl, hbmp, 0);
3746 ok(r == 1, "should be one\n");
3748 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3749 expect(0, r);
3751 item.mask = LVIF_IMAGE;
3752 item.iImage = 0;
3753 item.iItem = 0;
3754 item.iSubItem = 0;
3755 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3756 expect(TRUE, r);
3757 /* on state icon */
3758 x = pos.x + 8;
3759 y = pos.y + (bounds.bottom - bounds.top) / 2;
3760 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3761 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3762 y = (bounds.bottom - bounds.top) / 2;
3763 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3765 /* state icons indices are 1 based, check with valid index */
3766 item.mask = LVIF_STATE;
3767 item.state = INDEXTOSTATEIMAGEMASK(1);
3768 item.stateMask = LVIS_STATEIMAGEMASK;
3769 item.iItem = 0;
3770 item.iSubItem = 0;
3771 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3772 expect(TRUE, r);
3773 /* on state icon */
3774 x = pos.x + 8;
3775 y = pos.y + (bounds.bottom - bounds.top) / 2;
3776 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3777 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3778 y = (bounds.bottom - bounds.top) / 2;
3779 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3781 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3782 ok(himl2 == himl, "should return handle\n");
3784 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3785 expect(0, r);
3786 /* on item icon */
3787 x = pos.x + 8;
3788 y = pos.y + (bounds.bottom - bounds.top) / 2;
3789 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3790 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3791 y = (bounds.bottom - bounds.top) / 2;
3792 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3794 DestroyWindow(hwnd);
3797 static void test_getviewrect(void)
3799 HWND hwnd;
3800 DWORD r;
3801 RECT rect;
3802 LVITEMA item;
3804 hwnd = create_listview_control(LVS_REPORT);
3805 ok(hwnd != NULL, "failed to create a listview window\n");
3807 /* empty */
3808 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3809 expect(TRUE, r);
3811 insert_column(hwnd, 0);
3812 insert_column(hwnd, 1);
3814 memset(&item, 0, sizeof(item));
3815 item.iItem = 0;
3816 item.iSubItem = 0;
3817 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3818 ok(!r, "got %d\n", r);
3820 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3821 expect(TRUE, r);
3822 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3823 expect(TRUE, r);
3825 SetRect(&rect, -1, -1, -1, -1);
3826 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3827 expect(TRUE, r);
3828 /* left is set to (2e31-1) - XP SP2 */
3829 expect(0, rect.right);
3830 expect(0, rect.top);
3831 expect(0, rect.bottom);
3833 /* switch to LVS_ICON */
3834 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
3836 SetRect(&rect, -1, -1, -1, -1);
3837 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3838 expect(TRUE, r);
3839 expect(0, rect.left);
3840 expect(0, rect.top);
3841 /* precise value differs for 2k, XP and Vista */
3842 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3843 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3845 DestroyWindow(hwnd);
3848 static void test_getitemposition(void)
3850 HWND hwnd, header;
3851 DWORD r;
3852 POINT pt;
3853 RECT rect;
3855 hwnd = create_listview_control(LVS_REPORT);
3856 ok(hwnd != NULL, "failed to create a listview window\n");
3857 header = subclass_header(hwnd);
3859 /* LVS_REPORT, single item, no columns added */
3860 insert_item(hwnd, 0);
3862 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3864 pt.x = pt.y = -1;
3865 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3866 expect(TRUE, r);
3867 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3869 /* LVS_REPORT, single item, single column */
3870 insert_column(hwnd, 0);
3872 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3874 pt.x = pt.y = -1;
3875 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3876 expect(TRUE, r);
3877 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3879 SetRectEmpty(&rect);
3880 r = SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3881 ok(r, "got %d\n", r);
3882 /* some padding? */
3883 expect(2, pt.x);
3884 /* offset by header height */
3885 expect(rect.bottom - rect.top, pt.y);
3887 DestroyWindow(hwnd);
3890 static void test_columnscreation(void)
3892 HWND hwnd, header;
3893 DWORD r;
3895 hwnd = create_listview_control(LVS_REPORT);
3896 ok(hwnd != NULL, "failed to create a listview window\n");
3898 insert_item(hwnd, 0);
3900 /* headers columns aren't created automatically */
3901 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3902 ok(IsWindow(header), "Expected header handle\n");
3903 r = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
3904 expect(0, r);
3906 DestroyWindow(hwnd);
3909 static void test_getitemrect(void)
3911 HWND hwnd;
3912 HIMAGELIST himl, himl_ret;
3913 HBITMAP hbm;
3914 RECT rect;
3915 DWORD r;
3916 LVITEMA item;
3917 LVCOLUMNA col;
3918 INT order[2];
3919 POINT pt;
3921 /* rectangle isn't empty for empty text items */
3922 hwnd = create_listview_control(LVS_LIST);
3923 memset(&item, 0, sizeof(item));
3924 item.mask = 0;
3925 item.iItem = 0;
3926 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3927 expect(0, r);
3928 rect.left = LVIR_LABEL;
3929 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3930 expect(TRUE, r);
3931 expect(0, rect.left);
3932 expect(0, rect.top);
3933 /* estimate it as width / height ratio */
3934 todo_wine
3935 ok((rect.right / rect.bottom) >= 5, "got right %d, bottom %d\n", rect.right, rect.bottom);
3936 DestroyWindow(hwnd);
3938 hwnd = create_listview_control(LVS_REPORT);
3939 ok(hwnd != NULL, "failed to create a listview window\n");
3941 /* empty item */
3942 memset(&item, 0, sizeof(item));
3943 item.iItem = 0;
3944 item.iSubItem = 0;
3945 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3946 expect(0, r);
3948 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3949 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3950 expect(TRUE, r);
3952 /* zero width rectangle with no padding */
3953 expect(0, rect.left);
3954 expect(0, rect.right);
3956 insert_column(hwnd, 0);
3957 insert_column(hwnd, 1);
3959 col.mask = LVCF_WIDTH;
3960 col.cx = 50;
3961 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
3962 expect(TRUE, r);
3964 col.mask = LVCF_WIDTH;
3965 col.cx = 100;
3966 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
3967 expect(TRUE, r);
3969 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
3970 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3971 expect(TRUE, r);
3973 /* still no left padding */
3974 expect(0, rect.left);
3975 expect(150, rect.right);
3977 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
3978 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3979 expect(TRUE, r);
3980 /* padding */
3981 expect(2, rect.left);
3983 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
3984 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3985 expect(TRUE, r);
3986 /* padding, column width */
3987 expect(2, rect.left);
3988 expect(50, rect.right);
3990 /* no icons attached */
3991 SetRect(&rect, LVIR_ICON, -1, -1, -1);
3992 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3993 expect(TRUE, r);
3994 /* padding */
3995 expect(2, rect.left);
3996 expect(2, rect.right);
3998 /* change order */
3999 order[0] = 1; order[1] = 0;
4000 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4001 expect(TRUE, r);
4002 pt.x = -1;
4003 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4004 expect(TRUE, r);
4005 /* 1 indexed column width + padding */
4006 expect(102, pt.x);
4007 /* rect is at zero too */
4008 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4009 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4010 expect(TRUE, r);
4011 expect(0, rect.left);
4012 /* just width sum */
4013 expect(150, rect.right);
4015 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4016 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4017 expect(TRUE, r);
4018 /* column width + padding */
4019 expect(102, rect.left);
4021 /* back to initial order */
4022 order[0] = 0; order[1] = 1;
4023 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4024 expect(TRUE, r);
4026 /* state icons */
4027 himl = ImageList_Create(16, 16, 0, 2, 2);
4028 ok(himl != NULL, "failed to create imagelist\n");
4029 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4030 ok(hbm != NULL, "failed to create bitmap\n");
4031 r = ImageList_Add(himl, hbm, 0);
4032 expect(0, r);
4033 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4034 ok(hbm != NULL, "failed to create bitmap\n");
4035 r = ImageList_Add(himl, hbm, 0);
4036 expect(1, r);
4038 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4039 expect(0, r);
4041 item.mask = LVIF_STATE;
4042 item.state = INDEXTOSTATEIMAGEMASK(1);
4043 item.stateMask = LVIS_STATEIMAGEMASK;
4044 item.iItem = 0;
4045 item.iSubItem = 0;
4046 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4047 expect(TRUE, r);
4049 /* icon bounds */
4050 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4051 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4052 expect(TRUE, r);
4053 /* padding + stateicon width */
4054 expect(18, rect.left);
4055 expect(18, rect.right);
4056 /* label bounds */
4057 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4058 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4059 expect(TRUE, r);
4060 /* padding + stateicon width -> column width */
4061 expect(18, rect.left);
4062 expect(50, rect.right);
4064 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4065 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4067 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4068 expect(0, r);
4070 item.mask = LVIF_STATE | LVIF_IMAGE;
4071 item.iImage = 1;
4072 item.state = 0;
4073 item.stateMask = ~0;
4074 item.iItem = 0;
4075 item.iSubItem = 0;
4076 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4077 expect(TRUE, r);
4079 /* icon bounds */
4080 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4081 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4082 expect(TRUE, r);
4083 /* padding, icon width */
4084 expect(2, rect.left);
4085 expect(18, rect.right);
4086 /* label bounds */
4087 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4088 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4089 expect(TRUE, r);
4090 /* padding + icon width -> column width */
4091 expect(18, rect.left);
4092 expect(50, rect.right);
4094 /* select bounds */
4095 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4096 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4097 expect(TRUE, r);
4098 /* padding, column width */
4099 expect(2, rect.left);
4100 expect(50, rect.right);
4102 /* try with indentation */
4103 item.mask = LVIF_INDENT;
4104 item.iIndent = 1;
4105 item.iItem = 0;
4106 item.iSubItem = 0;
4107 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4108 expect(TRUE, r);
4110 /* bounds */
4111 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4112 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4113 expect(TRUE, r);
4114 /* padding + 1 icon width, column width */
4115 expect(0, rect.left);
4116 expect(150, rect.right);
4118 /* select bounds */
4119 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4120 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4121 expect(TRUE, r);
4122 /* padding + 1 icon width, column width */
4123 expect(2 + 16, rect.left);
4124 expect(50, rect.right);
4126 /* label bounds */
4127 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4128 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4129 expect(TRUE, r);
4130 /* padding + 2 icon widths, column width */
4131 expect(2 + 16*2, rect.left);
4132 expect(50, rect.right);
4134 /* icon bounds */
4135 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4136 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4137 expect(TRUE, r);
4138 /* padding + 1 icon width indentation, icon width */
4139 expect(2 + 16, rect.left);
4140 expect(34, rect.right);
4142 DestroyWindow(hwnd);
4145 static void test_editbox(void)
4147 static CHAR testitemA[] = "testitem";
4148 static CHAR testitem1A[] = "testitem_quitelongname";
4149 static CHAR testitem2A[] = "testITEM_quitelongname";
4150 static CHAR buffer[25];
4151 HWND hwnd, hwndedit, hwndedit2, header;
4152 LVITEMA item;
4153 INT r;
4155 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4156 ok(hwnd != NULL, "failed to create a listview window\n");
4158 insert_column(hwnd, 0);
4160 memset(&item, 0, sizeof(item));
4161 item.mask = LVIF_TEXT;
4162 item.pszText = testitemA;
4163 item.iItem = 0;
4164 item.iSubItem = 0;
4165 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4166 expect(0, r);
4168 /* test notifications without edit created */
4169 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4170 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4171 expect(0, r);
4172 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4173 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4174 /* same thing but with valid window */
4175 hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4176 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4177 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4178 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4179 expect(0, r);
4180 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4181 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4182 DestroyWindow(hwndedit);
4184 /* setting focus is necessary */
4185 SetFocus(hwnd);
4186 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4187 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4189 /* test children Z-order after Edit box created */
4190 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4191 ok(IsWindow(header), "Expected header to be created\n");
4192 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4193 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4195 /* modify initial string */
4196 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4197 expect(TRUE, r);
4199 /* edit window is resized and repositioned,
4200 check again for Z-order - it should be preserved */
4201 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4202 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4204 /* return focus to listview */
4205 SetFocus(hwnd);
4207 memset(&item, 0, sizeof(item));
4208 item.mask = LVIF_TEXT;
4209 item.pszText = buffer;
4210 item.cchTextMax = sizeof(buffer);
4211 item.iItem = 0;
4212 item.iSubItem = 0;
4213 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4214 expect(TRUE, r);
4216 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4218 /* send LVM_EDITLABEL on already created edit */
4219 SetFocus(hwnd);
4220 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4221 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4222 /* focus will be set to edit */
4223 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4224 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4225 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4227 /* creating label disabled when control isn't focused */
4228 SetFocus(0);
4229 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4230 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4232 /* check EN_KILLFOCUS handling */
4233 memset(&item, 0, sizeof(item));
4234 item.pszText = testitemA;
4235 item.iItem = 0;
4236 item.iSubItem = 0;
4237 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4238 expect(TRUE, r);
4240 SetFocus(hwnd);
4241 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4242 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4243 /* modify edit and notify control that it lost focus */
4244 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4245 expect(TRUE, r);
4246 g_editbox_disp_info.item.pszText = NULL;
4247 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4248 expect(0, r);
4249 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4251 memset(&item, 0, sizeof(item));
4252 item.pszText = buffer;
4253 item.cchTextMax = sizeof(buffer);
4254 item.iItem = 0;
4255 item.iSubItem = 0;
4256 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4257 expect(lstrlenA(item.pszText), r);
4258 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4259 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4261 /* change item name to differ in casing only */
4262 SetFocus(hwnd);
4263 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4264 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4265 /* modify edit and notify control that it lost focus */
4266 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4267 expect(TRUE, r);
4268 g_editbox_disp_info.item.pszText = NULL;
4269 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4270 expect(0, r);
4271 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4273 memset(&item, 0, sizeof(item));
4274 item.pszText = buffer;
4275 item.cchTextMax = sizeof(buffer);
4276 item.iItem = 0;
4277 item.iSubItem = 0;
4278 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4279 expect(lstrlenA(item.pszText), r);
4280 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4281 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4283 /* end edit without saving */
4284 SetFocus(hwnd);
4285 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4286 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4287 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4288 expect(0, r);
4289 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4290 "edit box - end edit, no change, escape", TRUE);
4291 /* end edit with saving */
4292 SetFocus(hwnd);
4293 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4294 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4295 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4296 expect(0, r);
4297 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4298 "edit box - end edit, no change, return", TRUE);
4300 memset(&item, 0, sizeof(item));
4301 item.pszText = buffer;
4302 item.cchTextMax = sizeof(buffer);
4303 item.iItem = 0;
4304 item.iSubItem = 0;
4305 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4306 expect(lstrlenA(item.pszText), r);
4307 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4309 /* LVM_EDITLABEL with -1 destroys current edit */
4310 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4311 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4312 /* no edit present */
4313 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4314 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4315 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4316 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4317 /* edit present */
4318 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4319 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4320 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4321 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4322 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4323 /* check another negative value */
4324 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4325 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4326 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4327 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4328 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4329 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4330 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4331 /* and value greater than max item index */
4332 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4333 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4334 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4335 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4336 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4337 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4338 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4339 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4341 /* messaging tests */
4342 SetFocus(hwnd);
4343 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4344 blockEdit = FALSE;
4345 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4346 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4347 /* testing only sizing messages */
4348 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4349 "edit box create - sizing", FALSE);
4351 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4352 SetFocus(hwnd);
4353 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4354 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4355 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4356 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4357 expect(0, r);
4358 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4359 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4361 DestroyWindow(hwnd);
4364 static void test_notifyformat(void)
4366 HWND hwnd, header;
4367 DWORD r;
4369 hwnd = create_listview_control(LVS_REPORT);
4370 ok(hwnd != NULL, "failed to create a listview window\n");
4372 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4373 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4374 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4375 expect(0, r);
4376 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4377 /* set */
4378 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4379 expect(0, r);
4380 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4381 ok(r == 1, "Unexpected return value %d.\n", r);
4382 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4383 expect(1, r);
4384 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4385 expect(0, r);
4387 DestroyWindow(hwnd);
4389 /* test failure in parent WM_NOTIFYFORMAT */
4390 notifyFormat = 0;
4391 hwnd = create_listview_control(LVS_REPORT);
4392 ok(hwnd != NULL, "failed to create a listview window\n");
4393 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4394 ok(IsWindow(header), "expected header to be created\n");
4395 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4396 expect(0, r);
4397 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4398 ok( r == 1, "Expected 1, got %d\n", r );
4399 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4400 ok(r != 0, "Expected valid format\n");
4402 notifyFormat = NFR_UNICODE;
4403 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4404 expect(NFR_UNICODE, r);
4405 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4406 expect(1, r);
4407 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4408 ok( r == 1, "Expected 1, got %d\n", r );
4410 notifyFormat = NFR_ANSI;
4411 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4412 expect(NFR_ANSI, r);
4413 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4414 expect(0, r);
4415 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4416 ok( r == 1, "Expected 1, got %d\n", r );
4418 DestroyWindow(hwnd);
4420 hwndparentW = create_parent_window(TRUE);
4421 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4422 if (!IsWindow(hwndparentW)) return;
4424 notifyFormat = -1;
4425 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4426 ok(hwnd != NULL, "failed to create a listview window\n");
4427 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4428 ok(IsWindow(header), "expected header to be created\n");
4429 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4430 expect(1, r);
4431 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4432 expect(1, r);
4433 DestroyWindow(hwnd);
4434 /* receiving error code defaulting to ansi */
4435 notifyFormat = 0;
4436 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4437 ok(hwnd != NULL, "failed to create a listview window\n");
4438 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4439 ok(IsWindow(header), "expected header to be created\n");
4440 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4441 expect(0, r);
4442 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4443 expect(1, r);
4444 DestroyWindow(hwnd);
4445 /* receiving ansi code from unicode window, use it */
4446 notifyFormat = NFR_ANSI;
4447 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4448 ok(hwnd != NULL, "failed to create a listview window\n");
4449 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4450 ok(IsWindow(header), "expected header to be created\n");
4451 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4452 expect(0, r);
4453 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4454 expect(1, r);
4455 DestroyWindow(hwnd);
4456 /* unicode listview with ansi parent window */
4457 notifyFormat = -1;
4458 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4459 ok(hwnd != NULL, "failed to create a listview window\n");
4460 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4461 ok(IsWindow(header), "expected header to be created\n");
4462 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4463 expect(0, r);
4464 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4465 expect(1, r);
4466 DestroyWindow(hwnd);
4467 /* unicode listview with ansi parent window, return error code */
4468 notifyFormat = 0;
4469 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4470 ok(hwnd != NULL, "failed to create a listview window\n");
4471 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4472 ok(IsWindow(header), "expected header to be created\n");
4473 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4474 expect(0, r);
4475 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4476 expect(1, r);
4477 DestroyWindow(hwnd);
4479 DestroyWindow(hwndparentW);
4482 static void test_indentation(void)
4484 HWND hwnd;
4485 LVITEMA item;
4486 DWORD r;
4488 hwnd = create_listview_control(LVS_REPORT);
4489 ok(hwnd != NULL, "failed to create a listview window\n");
4491 memset(&item, 0, sizeof(item));
4492 item.mask = LVIF_INDENT;
4493 item.iItem = 0;
4494 item.iIndent = I_INDENTCALLBACK;
4495 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4496 expect(0, r);
4498 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4500 item.iItem = 0;
4501 item.mask = LVIF_INDENT;
4502 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4503 expect(TRUE, r);
4505 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4506 "get indent dispinfo", FALSE);
4508 DestroyWindow(hwnd);
4511 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4513 return 0;
4516 static BOOL is_below_comctl_5(void)
4518 HWND hwnd;
4519 BOOL ret;
4521 hwnd = create_listview_control(LVS_REPORT);
4522 ok(hwnd != NULL, "failed to create a listview window\n");
4523 insert_item(hwnd, 0);
4525 ret = SendMessageA(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4527 DestroyWindow(hwnd);
4529 return !ret;
4532 static void test_get_set_view(void)
4534 HWND hwnd;
4535 DWORD ret;
4536 DWORD_PTR style;
4538 /* test style->view mapping */
4539 hwnd = create_listview_control(LVS_REPORT);
4540 ok(hwnd != NULL, "failed to create a listview window\n");
4542 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4543 expect(LV_VIEW_DETAILS, ret);
4545 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4546 /* LVS_ICON == 0 */
4547 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4548 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4549 expect(LV_VIEW_ICON, ret);
4551 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4552 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4553 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4554 expect(LV_VIEW_SMALLICON, ret);
4556 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4557 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4558 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4559 expect(LV_VIEW_LIST, ret);
4561 /* switching view doesn't touch window style */
4562 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4563 expect(1, ret);
4564 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4565 ok(style & LVS_LIST, "Expected style to be preserved\n");
4566 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4567 expect(1, ret);
4568 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4569 ok(style & LVS_LIST, "Expected style to be preserved\n");
4570 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4571 expect(1, ret);
4572 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4573 ok(style & LVS_LIST, "Expected style to be preserved\n");
4575 /* now change window style to see if view is remapped */
4576 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4577 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4578 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4579 expect(LV_VIEW_SMALLICON, ret);
4581 DestroyWindow(hwnd);
4584 static void test_canceleditlabel(void)
4586 HWND hwnd, hwndedit;
4587 DWORD ret;
4588 CHAR buff[10];
4589 LVITEMA itema;
4590 static CHAR test[] = "test";
4591 static const CHAR test1[] = "test1";
4593 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4594 ok(hwnd != NULL, "failed to create a listview window\n");
4596 insert_item(hwnd, 0);
4598 /* try without edit created */
4599 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4600 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4601 expect(TRUE, ret);
4602 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4603 "cancel edit label without edit", FALSE);
4605 /* cancel without data change */
4606 SetFocus(hwnd);
4607 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4608 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4609 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4610 expect(TRUE, ret);
4611 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4613 /* cancel after data change */
4614 memset(&itema, 0, sizeof(itema));
4615 itema.pszText = test;
4616 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4617 expect(TRUE, ret);
4618 SetFocus(hwnd);
4619 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4620 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4621 ret = SetWindowTextA(hwndedit, test1);
4622 expect(1, ret);
4623 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4624 expect(TRUE, ret);
4625 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4626 memset(&itema, 0, sizeof(itema));
4627 itema.pszText = buff;
4628 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
4629 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4630 expect(5, ret);
4631 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4633 DestroyWindow(hwnd);
4636 static void test_mapidindex(void)
4638 HWND hwnd;
4639 INT ret;
4641 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4642 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4643 ok(hwnd != NULL, "failed to create a listview window\n");
4644 insert_item(hwnd, 0);
4645 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4646 expect(-1, ret);
4647 DestroyWindow(hwnd);
4649 hwnd = create_listview_control(LVS_REPORT);
4650 ok(hwnd != NULL, "failed to create a listview window\n");
4652 /* LVM_MAPINDEXTOID with invalid index */
4653 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4654 expect(-1, ret);
4656 insert_item(hwnd, 0);
4657 insert_item(hwnd, 1);
4659 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4660 expect(-1, ret);
4661 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4662 expect(-1, ret);
4664 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4665 expect(0, ret);
4666 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4667 expect(1, ret);
4668 /* remove 0 indexed item, id retained */
4669 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4670 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4671 expect(1, ret);
4672 /* new id starts from previous value */
4673 insert_item(hwnd, 1);
4674 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4675 expect(2, ret);
4677 /* get index by id */
4678 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4679 expect(-1, ret);
4680 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4681 expect(-1, ret);
4682 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4683 expect(0, ret);
4684 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4685 expect(1, ret);
4687 DestroyWindow(hwnd);
4690 static void test_getitemspacing(void)
4692 HWND hwnd;
4693 DWORD ret;
4694 INT cx, cy;
4695 HIMAGELIST himl40, himl80;
4697 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4698 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4700 /* LVS_ICON */
4701 hwnd = create_listview_control(LVS_ICON);
4702 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4703 expect(cx, LOWORD(ret));
4704 expect(cy, HIWORD(ret));
4706 /* now try with icons */
4707 himl40 = ImageList_Create(40, 40, 0, 4, 4);
4708 ok(himl40 != NULL, "failed to create imagelist\n");
4709 himl80 = ImageList_Create(80, 80, 0, 4, 4);
4710 ok(himl80 != NULL, "failed to create imagelist\n");
4711 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4712 expect(0, ret);
4714 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4715 /* spacing + icon size returned */
4716 expect(cx + 40, LOWORD(ret));
4717 expect(cy + 40, HIWORD(ret));
4718 /* try changing icon size */
4719 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4721 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4722 /* spacing + icon size returned */
4723 expect(cx + 80, LOWORD(ret));
4724 expect(cy + 80, HIWORD(ret));
4726 /* set own icon spacing */
4727 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4728 expect(cx + 80, LOWORD(ret));
4729 expect(cy + 80, HIWORD(ret));
4731 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4732 /* set size returned */
4733 expect(100, LOWORD(ret));
4734 expect(100, HIWORD(ret));
4736 /* now change image list - icon spacing should be unaffected */
4737 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4739 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4740 /* set size returned */
4741 expect(100, LOWORD(ret));
4742 expect(100, HIWORD(ret));
4744 /* spacing = 0 - keep previous value */
4745 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
4746 expect(100, LOWORD(ret));
4747 expect(100, HIWORD(ret));
4749 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4750 expect(100, LOWORD(ret));
4752 expect(0xFFFF, HIWORD(ret));
4754 if (sizeof(void*) == 8)
4756 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
4757 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
4758 expect(100, LOWORD(ret));
4759 expect(0xFFFF, HIWORD(ret));
4761 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4762 expect(0xFFFF, LOWORD(ret));
4763 expect(0xFFFF, HIWORD(ret));
4765 else
4767 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
4768 expect(100, LOWORD(ret));
4769 expect(0xFFFF, HIWORD(ret));
4771 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4772 /* spacing + icon size returned */
4773 expect(cx + 40, LOWORD(ret));
4774 expect(cy + 40, HIWORD(ret));
4776 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4777 ImageList_Destroy(himl80);
4778 DestroyWindow(hwnd);
4779 /* LVS_SMALLICON */
4780 hwnd = create_listview_control(LVS_SMALLICON);
4781 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4782 expect(cx, LOWORD(ret));
4783 expect(cy, HIWORD(ret));
4785 /* spacing does not depend on selected view type */
4786 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4787 expect(0, ret);
4789 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4790 /* spacing + icon size returned */
4791 expect(cx + 40, LOWORD(ret));
4792 expect(cy + 40, HIWORD(ret));
4794 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4795 ImageList_Destroy(himl40);
4796 DestroyWindow(hwnd);
4797 /* LVS_REPORT */
4798 hwnd = create_listview_control(LVS_REPORT);
4799 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4800 expect(cx, LOWORD(ret));
4801 expect(cy, HIWORD(ret));
4803 DestroyWindow(hwnd);
4804 /* LVS_LIST */
4805 hwnd = create_listview_control(LVS_LIST);
4806 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4807 expect(cx, LOWORD(ret));
4808 expect(cy, HIWORD(ret));
4810 DestroyWindow(hwnd);
4813 static INT get_current_font_height(HWND listview)
4815 TEXTMETRICA tm;
4816 HFONT hfont;
4817 HWND hwnd;
4818 HDC hdc;
4820 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
4821 if (!hwnd)
4822 hwnd = listview;
4824 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
4825 if (!hfont) {
4826 hdc = GetDC(hwnd);
4827 GetTextMetricsA(hdc, &tm);
4828 ReleaseDC(hwnd, hdc);
4830 else {
4831 HFONT oldfont;
4833 hdc = GetDC(0);
4834 oldfont = SelectObject(hdc, hfont);
4835 GetTextMetricsA(hdc, &tm);
4836 SelectObject(hdc, oldfont);
4837 ReleaseDC(0, hdc);
4840 return tm.tmHeight;
4843 static void test_getcolumnwidth(void)
4845 HWND hwnd;
4846 INT ret;
4847 DWORD_PTR style;
4848 LVCOLUMNA col;
4849 LVITEMA itema;
4850 INT height;
4852 /* default column width */
4853 hwnd = create_listview_control(LVS_ICON);
4854 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4855 expect(0, ret);
4856 style = GetWindowLongA(hwnd, GWL_STYLE);
4857 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
4858 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4859 todo_wine expect(8, ret);
4860 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
4861 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
4862 col.mask = 0;
4863 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4864 expect(0, ret);
4865 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4866 expect(10, ret);
4867 DestroyWindow(hwnd);
4869 /* default column width with item added */
4870 hwnd = create_listview_control(LVS_LIST);
4871 memset(&itema, 0, sizeof(itema));
4872 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4873 ok(!ret, "got %d\n", ret);
4874 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4875 height = get_current_font_height(hwnd);
4876 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
4877 DestroyWindow(hwnd);
4880 static void test_scrollnotify(void)
4882 HWND hwnd;
4883 DWORD ret;
4885 hwnd = create_listview_control(LVS_REPORT);
4887 insert_column(hwnd, 0);
4888 insert_column(hwnd, 1);
4889 insert_item(hwnd, 0);
4891 /* make it scrollable - resize */
4892 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4893 expect(TRUE, ret);
4894 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4895 expect(TRUE, ret);
4897 /* try with dummy call */
4898 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4899 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
4900 expect(TRUE, ret);
4901 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4902 "scroll notify 1", TRUE);
4904 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4905 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
4906 expect(TRUE, ret);
4907 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4908 "scroll notify 2", TRUE);
4910 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4911 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
4912 expect(TRUE, ret);
4913 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4914 "scroll notify 3", TRUE);
4916 DestroyWindow(hwnd);
4919 static void test_LVS_EX_TRANSPARENTBKGND(void)
4921 HWND hwnd;
4922 DWORD ret;
4923 HDC hdc;
4925 hwnd = create_listview_control(LVS_REPORT);
4927 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4928 expect(TRUE, ret);
4930 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4931 LVS_EX_TRANSPARENTBKGND);
4933 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
4934 if (ret != CLR_NONE)
4936 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4937 DestroyWindow(hwnd);
4938 return;
4941 /* try to set some back color and check this style bit */
4942 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4943 expect(TRUE, ret);
4944 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4945 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4947 /* now test what this style actually does */
4948 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4949 LVS_EX_TRANSPARENTBKGND);
4951 hdc = GetWindowDC(hwndparent);
4953 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4954 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4955 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4956 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4958 ReleaseDC(hwndparent, hdc);
4960 DestroyWindow(hwnd);
4963 static void test_approximate_viewrect(void)
4965 static CHAR test[] = "abracadabra, a very long item label";
4966 DWORD item_width, item_height, header_height;
4967 static CHAR column_header[] = "Header";
4968 unsigned const column_width = 100;
4969 DWORD ret, item_count;
4970 HIMAGELIST himl;
4971 LVITEMA itema;
4972 LVCOLUMNA col;
4973 HBITMAP hbmp;
4974 HWND hwnd;
4976 /* LVS_ICON */
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 ok(ret != 0, "Unexpected return value %#x.\n", ret);
4997 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4998 expect(MAKELONG(77,827), ret);
5000 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5001 ok(ret != 0, "got 0\n");
5003 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5004 expect(MAKELONG(102,302), ret);
5006 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5007 expect(MAKELONG(52,52), ret);
5009 itema.pszText = test;
5010 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5011 expect(TRUE, ret);
5012 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5013 expect(MAKELONG(52,52), ret);
5015 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5016 expect(MAKELONG(52,2), ret);
5017 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5018 expect(MAKELONG(52,52), ret);
5019 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5020 expect(MAKELONG(102,52), ret);
5021 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5022 expect(MAKELONG(102,102), ret);
5023 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5024 expect(MAKELONG(102,102), ret);
5025 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5026 expect(MAKELONG(102,152), ret);
5027 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5028 expect(MAKELONG(102,152), ret);
5029 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5030 expect(MAKELONG(152,152), ret);
5032 DestroyWindow(hwnd);
5034 /* LVS_REPORT */
5035 hwnd = create_listview_control(LVS_REPORT);
5037 /* Empty control without columns */
5038 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100, 100));
5039 todo_wine
5040 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5041 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5043 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5044 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5045 todo_wine
5046 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5048 header_height = HIWORD(ret);
5050 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5051 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5052 todo_wine
5053 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5055 item_height = HIWORD(ret) - header_height;
5057 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5058 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5059 ok(HIWORD(ret) == (header_height - 2 * item_height), "Unexpected height %d.\n", HIWORD(ret)) ;
5061 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5062 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5063 ok(HIWORD(ret) == header_height, "Unexpected height.\n");
5064 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5065 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5066 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5068 /* Insert column */
5069 col.mask = LVCF_TEXT | LVCF_WIDTH;
5070 col.pszText = column_header;
5071 col.cx = column_width;
5072 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5073 ok(ret == 0, "Unexpected return value %d.\n", ret);
5075 /* Empty control with column */
5076 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5077 todo_wine {
5078 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5079 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5081 header_height = HIWORD(ret);
5082 item_width = LOWORD(ret);
5084 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5085 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5086 todo_wine
5087 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5089 item_height = HIWORD(ret) - header_height;
5091 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5092 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5093 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5095 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5096 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5097 ok(HIWORD(ret) == header_height, "Unexpected height %d.\n", HIWORD(ret));
5099 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5100 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5101 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5103 for (item_count = 1; item_count <= 2; ++item_count)
5105 itema.mask = LVIF_TEXT;
5106 itema.iItem = 0;
5107 itema.iSubItem = 0;
5108 itema.pszText = test;
5109 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5110 ok(ret == 0, "Unexpected return value %d.\n", ret);
5112 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5113 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5114 todo_wine
5115 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5117 header_height = HIWORD(ret);
5118 item_width = LOWORD(ret);
5120 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5121 ok(LOWORD(ret) == item_width, "Unexpected width %d, item %d\n", LOWORD(ret), item_count - 1);
5122 ok(HIWORD(ret) > header_height, "Unexpected height %d. item %d.\n", HIWORD(ret), item_count - 1);
5124 item_height = HIWORD(ret) - header_height;
5126 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5127 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5128 todo_wine
5129 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5131 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5132 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5133 ok(HIWORD(ret) == header_height + item_count * item_height, "Unexpected height %d.\n", HIWORD(ret));
5135 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5136 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5137 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5139 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELONG(item_width * 2, header_height + 3 * item_height));
5140 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5141 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5143 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(item_width * 2, 0));
5144 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5145 todo_wine
5146 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5148 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(-1, -1));
5149 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5150 todo_wine
5151 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5154 DestroyWindow(hwnd);
5158 static void test_finditem(void)
5160 LVFINDINFOA fi;
5161 static char f[5];
5162 HWND hwnd;
5163 INT r;
5165 hwnd = create_listview_control(LVS_REPORT);
5166 insert_item(hwnd, 0);
5168 memset(&fi, 0, sizeof(fi));
5170 /* full string search, inserted text was "foo" */
5171 strcpy(f, "foo");
5172 fi.flags = LVFI_STRING;
5173 fi.psz = f;
5174 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5175 expect(0, r);
5177 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5178 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5179 expect(0, r);
5181 fi.flags = LVFI_PARTIAL;
5182 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5183 expect(0, r);
5185 /* partial string search, inserted text was "foo" */
5186 strcpy(f, "fo");
5187 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5188 fi.psz = f;
5189 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5190 expect(0, r);
5192 fi.flags = LVFI_STRING;
5193 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5194 expect(-1, r);
5196 fi.flags = LVFI_PARTIAL;
5197 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5198 expect(0, r);
5200 /* partial string search, part after start char */
5201 strcpy(f, "oo");
5202 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5203 fi.psz = f;
5204 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5205 expect(-1, r);
5207 /* try with LVFI_SUBSTRING */
5208 strcpy(f, "fo");
5209 fi.flags = LVFI_SUBSTRING;
5210 fi.psz = f;
5211 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5212 expect(0, r);
5213 strcpy(f, "f");
5214 fi.flags = LVFI_SUBSTRING;
5215 fi.psz = f;
5216 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5217 expect(0, r);
5218 strcpy(f, "o");
5219 fi.flags = LVFI_SUBSTRING;
5220 fi.psz = f;
5221 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5222 expect(-1, r);
5224 strcpy(f, "o");
5225 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5226 fi.psz = f;
5227 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5228 expect(-1, r);
5230 strcpy(f, "f");
5231 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5232 fi.psz = f;
5233 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5234 expect(0, r);
5236 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5237 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5238 expect(0, r);
5240 DestroyWindow(hwnd);
5243 static void test_LVS_EX_HEADERINALLVIEWS(void)
5245 HWND hwnd, header;
5246 DWORD style;
5248 hwnd = create_listview_control(LVS_ICON);
5250 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5251 LVS_EX_HEADERINALLVIEWS);
5253 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5254 if (!IsWindow(header))
5256 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5257 DestroyWindow(hwnd);
5258 return;
5261 /* LVS_NOCOLUMNHEADER works as before */
5262 style = GetWindowLongA(hwnd, GWL_STYLE);
5263 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5264 style = GetWindowLongA(header, GWL_STYLE);
5265 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5266 style = GetWindowLongA(hwnd, GWL_STYLE);
5267 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5268 style = GetWindowLongA(header, GWL_STYLE);
5269 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5271 /* try to remove style */
5272 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5273 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5274 ok(IsWindow(header), "Expected header to be created\n");
5275 style = GetWindowLongA(header, GWL_STYLE);
5276 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5278 DestroyWindow(hwnd);
5280 /* check other styles */
5281 hwnd = create_listview_control(LVS_LIST);
5282 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5283 LVS_EX_HEADERINALLVIEWS);
5284 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5285 ok(IsWindow(header), "Expected header to be created\n");
5286 DestroyWindow(hwnd);
5288 hwnd = create_listview_control(LVS_SMALLICON);
5289 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5290 LVS_EX_HEADERINALLVIEWS);
5291 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5292 ok(IsWindow(header), "Expected header to be created\n");
5293 DestroyWindow(hwnd);
5295 hwnd = create_listview_control(LVS_REPORT);
5296 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5297 LVS_EX_HEADERINALLVIEWS);
5298 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5299 ok(IsWindow(header), "Expected header to be created\n");
5300 DestroyWindow(hwnd);
5303 static void test_hover(void)
5305 HWND hwnd, fg;
5306 DWORD r;
5308 hwnd = create_listview_control(LVS_ICON);
5309 SetForegroundWindow(hwndparent);
5310 fg = GetForegroundWindow();
5311 if (fg != hwndparent)
5313 skip("Window is not in the foreground. Skipping hover tests.\n");
5314 DestroyWindow(hwnd);
5315 return;
5318 /* test WM_MOUSEHOVER forwarding */
5319 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5320 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5321 expect(0, r);
5322 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5323 g_block_hover = TRUE;
5324 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5325 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5326 expect(0, r);
5327 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5328 g_block_hover = FALSE;
5330 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5331 expect(HOVER_DEFAULT, r);
5332 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5333 expect(500, r);
5335 DestroyWindow(hwnd);
5338 static void test_destroynotify(void)
5340 HWND hwnd;
5341 BOOL ret;
5343 hwnd = create_listview_control(LVS_REPORT);
5344 ok(hwnd != NULL, "failed to create listview window\n");
5346 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5347 DestroyWindow(hwnd);
5348 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5350 /* same for ownerdata list */
5351 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5352 ok(hwnd != NULL, "failed to create listview window\n");
5354 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5355 DestroyWindow(hwnd);
5356 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5358 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5359 ok(hwnd != NULL, "failed to create listview window\n");
5361 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5362 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5363 ok(ret == TRUE, "got %d\n", ret);
5364 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5365 DestroyWindow(hwnd);
5368 static void test_header_notification(void)
5370 static char textA[] = "newtext";
5371 HWND list, header;
5372 HDITEMA item;
5373 NMHEADERA nmh;
5374 LVCOLUMNA col;
5375 DWORD ret;
5376 BOOL r;
5378 list = create_listview_control(LVS_REPORT);
5379 ok(list != NULL, "failed to create listview window\n");
5381 memset(&col, 0, sizeof(col));
5382 col.mask = LVCF_WIDTH;
5383 col.cx = 100;
5384 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5385 expect(0, ret);
5387 /* check list parent notification after header item changed,
5388 this test should be placed before header subclassing to avoid
5389 Listview -> Header messages to be logged */
5390 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5392 col.mask = LVCF_TEXT;
5393 col.pszText = textA;
5394 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5395 expect(TRUE, r);
5397 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5398 "header notify, listview", FALSE);
5399 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5400 "header notify, parent", FALSE);
5402 header = subclass_header(list);
5404 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5405 expect(1, ret);
5407 memset(&item, 0, sizeof(item));
5408 item.mask = HDI_WIDTH;
5409 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5410 expect(1, ret);
5411 expect(100, item.cxy);
5413 nmh.hdr.hwndFrom = header;
5414 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5415 nmh.hdr.code = HDN_ITEMCHANGEDA;
5416 nmh.iItem = 0;
5417 nmh.iButton = 0;
5418 item.mask = HDI_WIDTH;
5419 item.cxy = 50;
5420 nmh.pitem = &item;
5421 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5422 expect(0, ret);
5424 DestroyWindow(list);
5427 static void test_header_notification2(void)
5429 static char textA[] = "newtext";
5430 HWND list, header;
5431 HDITEMW itemW;
5432 NMHEADERW nmhdr;
5433 LVCOLUMNA col;
5434 DWORD ret;
5435 WCHAR buffer[100];
5436 struct message parent_header_notify_seq[] = {
5437 { WM_NOTIFY, sent|id, 0, 0, 0 },
5438 { 0 }
5441 list = create_listview_control(LVS_REPORT);
5442 ok(list != NULL, "failed to create listview window\n");
5444 memset(&col, 0, sizeof(col));
5445 col.mask = LVCF_WIDTH | LVCF_TEXT;
5446 col.cx = 100;
5447 col.pszText = textA;
5448 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5449 expect(0, ret);
5451 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5452 ok(header != 0, "No header\n");
5453 memset(&itemW, 0, sizeof(itemW));
5454 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5455 itemW.pszText = buffer;
5456 itemW.cchTextMax = sizeof(buffer);
5457 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5458 expect(1, ret);
5460 nmhdr.hdr.hwndFrom = header;
5461 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5462 nmhdr.iItem = 0;
5463 nmhdr.iButton = 0;
5464 nmhdr.pitem = &itemW;
5466 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5467 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5468 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5469 ok(ret == 0, "got %d\n", ret);
5470 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5471 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5472 "header notify, parent", TRUE);
5473 todo_wine
5474 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5475 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5476 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5477 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5478 ok(ret == 0, "got %d\n", ret);
5479 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5480 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5481 "header notify, parent", TRUE);
5482 todo_wine
5483 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5484 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5485 SetFocus(list);
5486 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5487 nmhdr.hdr.code = HDN_ITEMCLICKW;
5488 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5489 ok(ret == 0, "got %d\n", ret);
5490 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5491 "header notify, parent", FALSE);
5492 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5493 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5494 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5495 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5496 ok(ret == 0, "got %d\n", ret);
5497 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5498 "header notify, parent", FALSE);
5499 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5500 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5501 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5502 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5503 ok(ret == 0, "got %d\n", ret);
5504 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5505 "header notify, parent", TRUE);
5506 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5507 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5508 nmhdr.hdr.code = HDN_BEGINTRACKW;
5509 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5510 ok(ret == 0, "got %d\n", ret);
5511 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5512 "header notify, parent", FALSE);
5513 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5514 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5515 nmhdr.hdr.code = HDN_ENDTRACKW;
5516 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5517 ok(ret == 0, "got %d\n", ret);
5518 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5519 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5520 "header notify, parent", FALSE);
5521 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5522 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5523 nmhdr.hdr.code = HDN_TRACKW;
5524 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5525 ok(ret == 0, "got %d\n", ret);
5526 parent_header_notify_seq[0].id = HDN_TRACKA;
5527 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5528 "header notify, parent", FALSE);
5529 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5530 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5531 nmhdr.hdr.code = HDN_BEGINDRAG;
5532 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5533 ok(ret == 1, "got %d\n", ret);
5534 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5535 "header notify, parent", FALSE);
5536 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5537 nmhdr.hdr.code = HDN_ENDDRAG;
5538 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5539 ok(ret == 0, "got %d\n", ret);
5540 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5541 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5542 "header notify, parent", FALSE);
5543 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5544 nmhdr.hdr.code = HDN_FILTERCHANGE;
5545 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5546 ok(ret == 0, "got %d\n", ret);
5547 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5548 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5549 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5550 "header notify, parent", FALSE);
5551 parent_header_notify_seq[0].flags &= ~optional;
5552 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5553 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5554 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5555 ok(ret == 0, "got %d\n", ret);
5556 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5557 "header notify, parent", FALSE);
5558 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5559 nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5560 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5561 ok(ret == 0, "got %d\n", ret);
5562 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5563 "header notify, parent", FALSE);
5564 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5565 nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5566 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5567 ok(ret == 0, "got %d\n", ret);
5568 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5569 "header notify, parent", FALSE);
5570 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5571 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5572 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5573 ok(ret == 0, "got %d\n", ret);
5574 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5575 "header notify, parent", FALSE);
5577 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5579 DestroyWindow(list);
5582 static void test_createdragimage(void)
5584 HIMAGELIST himl;
5585 POINT pt;
5586 HWND list;
5588 list = create_listview_control(LVS_ICON);
5589 ok(list != NULL, "failed to create listview window\n");
5591 insert_item(list, 0);
5593 /* NULL point */
5594 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5595 ok(himl == NULL, "got %p\n", himl);
5597 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5598 ok(himl != NULL, "got %p\n", himl);
5599 ImageList_Destroy(himl);
5601 DestroyWindow(list);
5604 static void test_dispinfo(void)
5606 static const char testA[] = "TEST";
5607 WCHAR buff[10];
5608 LVITEMA item;
5609 HWND hwnd;
5610 DWORD ret;
5612 hwnd = create_listview_control(LVS_ICON);
5613 ok(hwnd != NULL, "failed to create listview window\n");
5615 insert_item(hwnd, 0);
5617 memset(&item, 0, sizeof(item));
5618 item.pszText = LPSTR_TEXTCALLBACKA;
5619 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5620 expect(1, ret);
5622 g_disp_A_to_W = TRUE;
5623 item.pszText = (char*)buff;
5624 item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
5625 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5626 ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
5627 g_disp_A_to_W = FALSE;
5629 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5630 "got %s, expected %s\n", item.pszText, testA);
5632 DestroyWindow(hwnd);
5635 static void test_LVM_SETITEMTEXT(void)
5637 static char testA[] = "TEST";
5638 LVITEMA item;
5639 HWND hwnd;
5640 DWORD ret;
5642 hwnd = create_listview_control(LVS_ICON);
5643 ok(hwnd != NULL, "failed to create listview window\n");
5645 insert_item(hwnd, 0);
5647 /* null item pointer */
5648 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5649 expect(FALSE, ret);
5651 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5652 expect(FALSE, ret);
5654 /* index out of bounds */
5655 item.pszText = testA;
5656 item.cchTextMax = 0; /* ignored */
5657 item.iSubItem = 0;
5659 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5660 expect(FALSE, ret);
5662 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5663 expect(FALSE, ret);
5665 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5666 expect(TRUE, ret);
5668 DestroyWindow(hwnd);
5671 static void test_LVM_REDRAWITEMS(void)
5673 HWND list;
5674 DWORD ret;
5676 list = create_listview_control(LVS_ICON);
5677 ok(list != NULL, "failed to create listview window\n");
5679 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5680 expect(TRUE, ret);
5682 insert_item(list, 0);
5684 ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
5685 expect(TRUE, ret);
5687 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
5688 expect(TRUE, ret);
5690 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5691 expect(TRUE, ret);
5693 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
5694 expect(TRUE, ret);
5696 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
5697 expect(TRUE, ret);
5699 ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
5700 expect(TRUE, ret);
5702 ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
5703 expect(TRUE, ret);
5705 DestroyWindow(list);
5708 static void test_imagelists(void)
5710 HWND hwnd, header;
5711 HIMAGELIST himl1, himl2, himl3;
5712 LRESULT ret;
5714 himl1 = ImageList_Create(40, 40, 0, 4, 4);
5715 himl2 = ImageList_Create(40, 40, 0, 4, 4);
5716 himl3 = ImageList_Create(40, 40, 0, 4, 4);
5717 ok(himl1 != NULL, "Failed to create imagelist\n");
5718 ok(himl2 != NULL, "Failed to create imagelist\n");
5719 ok(himl3 != NULL, "Failed to create imagelist\n");
5721 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5722 header = subclass_header(hwnd);
5724 ok(header != NULL, "Expected header\n");
5725 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5726 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5728 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5730 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5731 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5732 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5733 "set normal image list", FALSE);
5735 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5737 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5738 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5739 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5740 "set state image list", TRUE);
5742 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5743 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5745 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5747 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5748 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5749 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
5750 "set small image list", FALSE);
5752 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5753 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5754 DestroyWindow(hwnd);
5756 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
5758 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5760 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5761 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5762 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5763 "set normal image list", FALSE);
5765 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5767 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5768 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5769 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5770 "set state image list", FALSE);
5772 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5774 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5775 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5776 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5777 "set small image list", FALSE);
5779 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5780 ok(header == NULL, "Expected no header, got %p\n", header);
5782 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
5784 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5785 ok(header != NULL, "Expected header, got NULL\n");
5787 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5788 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5790 DestroyWindow(hwnd);
5793 static void test_deleteitem(void)
5795 LVITEMA item;
5796 UINT state;
5797 HWND hwnd;
5798 BOOL ret;
5800 hwnd = create_listview_control(LVS_REPORT);
5802 insert_item(hwnd, 0);
5803 insert_item(hwnd, 0);
5804 insert_item(hwnd, 0);
5805 insert_item(hwnd, 0);
5806 insert_item(hwnd, 0);
5808 g_focus_test_LVN_DELETEITEM = TRUE;
5810 /* delete focused item (not the last index) */
5811 item.stateMask = LVIS_FOCUSED;
5812 item.state = LVIS_FOCUSED;
5813 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
5814 ok(ret == TRUE, "got %d\n", ret);
5815 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
5816 ok(ret == TRUE, "got %d\n", ret);
5817 /* next item gets focus */
5818 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5819 ok(state == LVIS_FOCUSED, "got %x\n", state);
5821 /* focus last item and delete it */
5822 item.stateMask = LVIS_FOCUSED;
5823 item.state = LVIS_FOCUSED;
5824 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
5825 ok(ret == TRUE, "got %d\n", ret);
5826 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
5827 ok(ret == TRUE, "got %d\n", ret);
5828 /* new last item gets focus */
5829 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5830 ok(state == LVIS_FOCUSED, "got %x\n", state);
5832 /* focus first item and delete it */
5833 item.stateMask = LVIS_FOCUSED;
5834 item.state = LVIS_FOCUSED;
5835 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
5836 ok(ret == TRUE, "got %d\n", ret);
5837 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
5838 ok(ret == TRUE, "got %d\n", ret);
5839 /* new first item gets focus */
5840 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5841 ok(state == LVIS_FOCUSED, "got %x\n", state);
5843 g_focus_test_LVN_DELETEITEM = FALSE;
5845 DestroyWindow(hwnd);
5848 static void test_insertitem(void)
5850 LVITEMA item;
5851 UINT state;
5852 HWND hwnd;
5853 INT ret;
5855 hwnd = create_listview_control(LVS_REPORT);
5857 /* insert item 0 focused */
5858 item.mask = LVIF_STATE;
5859 item.state = LVIS_FOCUSED;
5860 item.stateMask = LVIS_FOCUSED;
5861 item.iItem = 0;
5862 item.iSubItem = 0;
5863 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5864 ok(ret == 0, "got %d\n", ret);
5866 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5867 ok(state == LVIS_FOCUSED, "got %x\n", state);
5869 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5871 /* insert item 1, focus shift */
5872 item.mask = LVIF_STATE;
5873 item.state = LVIS_FOCUSED;
5874 item.stateMask = LVIS_FOCUSED;
5875 item.iItem = 1;
5876 item.iSubItem = 0;
5877 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5878 ok(ret == 1, "got %d\n", ret);
5880 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
5882 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5883 ok(state == LVIS_FOCUSED, "got %x\n", state);
5885 /* insert item 2, no focus shift */
5886 item.mask = LVIF_STATE;
5887 item.state = 0;
5888 item.stateMask = LVIS_FOCUSED;
5889 item.iItem = 2;
5890 item.iSubItem = 0;
5891 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5892 ok(ret == 2, "got %d\n", ret);
5894 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5895 ok(state == LVIS_FOCUSED, "got %x\n", state);
5897 DestroyWindow(hwnd);
5900 static void test_header_proc(void)
5902 HWND hwnd, header, hdr;
5903 WNDPROC proc1, proc2;
5905 hwnd = create_listview_control(LVS_REPORT);
5907 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5908 ok(header != NULL, "got %p\n", header);
5910 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
5911 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
5912 0, 0, 0, 0,
5913 NULL, NULL, NULL, NULL);
5914 ok(hdr != NULL, "got %p\n", hdr);
5916 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
5917 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
5918 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
5920 DestroyWindow(hdr);
5921 DestroyWindow(hwnd);
5924 static void flush_events(void)
5926 MSG msg;
5927 int diff = 200;
5928 int min_timeout = 100;
5929 DWORD time = GetTickCount() + diff;
5931 while (diff > 0)
5933 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
5934 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
5935 diff = time - GetTickCount();
5939 static void test_oneclickactivate(void)
5941 TRACKMOUSEEVENT track;
5942 char item1[] = "item1";
5943 LVITEMA item;
5944 HWND hwnd, fg;
5945 RECT rect;
5946 INT r;
5947 POINT orig_pos;
5949 hwnd = CreateWindowExA(0, "SysListView32", "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
5950 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
5951 ok(hwnd != NULL, "failed to create listview window\n");
5952 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
5953 ok(r == 0, "should return zero\n");
5955 SetForegroundWindow(hwndparent);
5956 flush_events();
5957 fg = GetForegroundWindow();
5958 if (fg != hwndparent)
5960 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
5961 DestroyWindow(hwnd);
5962 return;
5965 item.mask = LVIF_TEXT;
5966 item.iItem = 0;
5967 item.iSubItem = 0;
5968 item.iImage = 0;
5969 item.pszText = item1;
5970 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
5971 ok(r == 0, "should not fail\n");
5973 GetWindowRect(hwnd, &rect);
5974 GetCursorPos(&orig_pos);
5975 SetCursorPos(rect.left+5, rect.top+5);
5976 flush_events();
5977 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
5978 expect(0, r);
5980 track.cbSize = sizeof(track);
5981 track.dwFlags = TME_QUERY;
5982 _TrackMouseEvent(&track);
5983 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
5984 ok(track.dwFlags == TME_LEAVE, "dwFlags = %x\n", track.dwFlags);
5986 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5987 expect(0, r);
5988 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
5989 expect(0, r);
5990 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
5991 expect(1, r);
5993 DestroyWindow(hwnd);
5994 SetCursorPos(orig_pos.x, orig_pos.y);
5997 static void test_callback_mask(void)
5999 DWORD mask;
6000 HWND hwnd;
6001 BOOL ret;
6003 hwnd = create_listview_control(LVS_REPORT);
6005 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 0);
6006 ok(ret, "got %d\n", ret);
6008 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 1);
6009 ok(ret, "got %d\n", ret);
6011 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6012 ok(mask == ~0u, "got 0x%08x\n", mask);
6014 DestroyWindow(hwnd);
6017 START_TEST(listview)
6019 HMODULE hComctl32;
6020 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
6022 ULONG_PTR ctx_cookie;
6023 HANDLE hCtx;
6025 hComctl32 = GetModuleHandleA("comctl32.dll");
6026 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
6027 if (pInitCommonControlsEx)
6029 INITCOMMONCONTROLSEX iccex;
6030 iccex.dwSize = sizeof(iccex);
6031 iccex.dwICC = ICC_LISTVIEW_CLASSES;
6032 pInitCommonControlsEx(&iccex);
6034 else
6035 InitCommonControls();
6037 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
6039 hwndparent = create_parent_window(FALSE);
6040 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6042 g_is_below_5 = is_below_comctl_5();
6044 test_header_notification();
6045 test_header_notification2();
6046 test_images();
6047 test_checkboxes();
6048 test_items();
6049 test_create();
6050 test_redraw();
6051 test_customdraw();
6052 test_icon_spacing();
6053 test_color();
6054 test_item_count();
6055 test_item_position();
6056 test_columns();
6057 test_getorigin();
6058 test_multiselect();
6059 test_getitemrect();
6060 test_subitem_rect();
6061 test_sorting();
6062 test_ownerdata();
6063 test_norecompute();
6064 test_nosortheader();
6065 test_setredraw();
6066 test_hittest();
6067 test_getviewrect();
6068 test_getitemposition();
6069 test_columnscreation();
6070 test_editbox();
6071 test_notifyformat();
6072 test_indentation();
6073 test_getitemspacing();
6074 test_getcolumnwidth();
6075 test_approximate_viewrect();
6076 test_finditem();
6077 test_hover();
6078 test_destroynotify();
6079 test_createdragimage();
6080 test_dispinfo();
6081 test_LVM_SETITEMTEXT();
6082 test_LVM_REDRAWITEMS();
6083 test_imagelists();
6084 test_deleteitem();
6085 test_insertitem();
6086 test_header_proc();
6087 test_oneclickactivate();
6088 test_callback_mask();
6090 if (!load_v6_module(&ctx_cookie, &hCtx))
6092 DestroyWindow(hwndparent);
6093 return;
6096 /* comctl32 version 6 tests start here */
6097 test_get_set_view();
6098 test_canceleditlabel();
6099 test_mapidindex();
6100 test_scrollnotify();
6101 test_LVS_EX_TRANSPARENTBKGND();
6102 test_LVS_EX_HEADERINALLVIEWS();
6103 test_deleteitem();
6104 test_multiselect();
6105 test_insertitem();
6106 test_header_proc();
6108 unload_v6_module(ctx_cookie, hCtx);
6110 DestroyWindow(hwndparent);