Release 1.5.29.
[wine] / dlls / comctl32 / tests / listview.c
1 /*
2  * ListView tests
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  * Copyright 2007 George Gov
6  * Copyright 2009-2013 Nikolay Sivov
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <stdio.h>
24 #include <windows.h>
25 #include <commctrl.h>
26
27 #include "wine/test.h"
28 #include "v6util.h"
29 #include "msg.h"
30
31 #define PARENT_SEQ_INDEX       0
32 #define PARENT_FULL_SEQ_INDEX  1
33 #define LISTVIEW_SEQ_INDEX     2
34 #define EDITBOX_SEQ_INDEX      3
35 #define COMBINED_SEQ_INDEX     4
36 #define NUM_MSG_SEQUENCES      5
37
38 #define LISTVIEW_ID 0
39 #define HEADER_ID   1
40
41 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
42 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
43        "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
44
45 static const WCHAR testparentclassW[] =
46     {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
47
48 static HWND hwndparent, hwndparentW;
49 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
50 static BOOL blockEdit;
51 /* return nonzero on NM_HOVER */
52 static BOOL g_block_hover;
53 /* notification data for LVN_ITEMCHANGED */
54 static NMLISTVIEW g_nmlistview;
55 /* notification data for LVN_ITEMCHANGING */
56 static NMLISTVIEW g_nmlistview_changing;
57 /* format reported to control:
58    -1 falls to defproc, anything else returned */
59 static INT notifyFormat;
60 /* indicates we're running < 5.80 version */
61 static BOOL g_is_below_5;
62 /* item data passed to LVN_GETDISPINFOA */
63 static LVITEMA g_itema;
64 /* alter notification code A->W */
65 static BOOL g_disp_A_to_W;
66 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
67 static NMLVDISPINFO g_editbox_disp_info;
68 /* when this is set focus will be tested on LVN_DELETEITEM */
69 static BOOL g_focus_test_LVN_DELETEITEM;
70
71 static HWND subclass_editbox(HWND hwndListview);
72
73 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
74
75 static const struct message create_ownerdrawfixed_parent_seq[] = {
76     { WM_NOTIFYFORMAT, sent },
77     { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
78     { WM_MEASUREITEM, sent },
79     { WM_PARENTNOTIFY, sent },
80     { 0 }
81 };
82
83 static const struct message redraw_listview_seq[] = {
84     { WM_PAINT,      sent|id,            0, 0, LISTVIEW_ID },
85     { WM_PAINT,      sent|id,            0, 0, HEADER_ID },
86     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, HEADER_ID },
87     { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
88     { WM_NOTIFY,     sent|id|defwinproc, 0, 0, LISTVIEW_ID },
89     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, LISTVIEW_ID },
90     { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
91     { 0 }
92 };
93
94 static const struct message listview_icon_spacing_seq[] = {
95     { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
96     { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
97     { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
98     { 0 }
99 };
100
101 static const struct message listview_color_seq[] = {
102     { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(0,0,0) },
103     { LVM_GETBKCOLOR,     sent },
104     { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(0,0,0) },
105     { LVM_GETTEXTCOLOR,   sent },
106     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
107     { LVM_GETTEXTBKCOLOR, sent },
108
109     { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(100,50,200) },
110     { LVM_GETBKCOLOR,     sent },
111     { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(100,50,200) },
112     { LVM_GETTEXTCOLOR,   sent },
113     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
114     { LVM_GETTEXTBKCOLOR, sent },
115
116     { LVM_SETBKCOLOR,     sent|lparam, 0, CLR_NONE },
117     { LVM_GETBKCOLOR,     sent },
118     { LVM_SETTEXTCOLOR,   sent|lparam, 0, CLR_NONE },
119     { LVM_GETTEXTCOLOR,   sent },
120     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
121     { LVM_GETTEXTBKCOLOR, sent },
122
123     { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(255,255,255) },
124     { LVM_GETBKCOLOR,     sent },
125     { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(255,255,255) },
126     { LVM_GETTEXTCOLOR,   sent },
127     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
128     { LVM_GETTEXTBKCOLOR, sent },
129     { 0 }
130 };
131
132 static const struct message listview_item_count_seq[] = {
133     { LVM_GETITEMCOUNT,   sent },
134     { LVM_INSERTITEM,     sent },
135     { LVM_INSERTITEM,     sent },
136     { LVM_INSERTITEM,     sent },
137     { LVM_GETITEMCOUNT,   sent },
138     { LVM_DELETEITEM,     sent|wparam, 2 },
139     { WM_NCPAINT,         sent|optional },
140     { WM_ERASEBKGND,      sent|optional },
141     { LVM_GETITEMCOUNT,   sent },
142     { LVM_DELETEALLITEMS, sent },
143     { LVM_GETITEMCOUNT,   sent },
144     { LVM_INSERTITEM,     sent },
145     { LVM_INSERTITEM,     sent },
146     { LVM_GETITEMCOUNT,   sent },
147     { LVM_INSERTITEM,     sent },
148     { LVM_GETITEMCOUNT,   sent },
149     { 0 }
150 };
151
152 static const struct message listview_itempos_seq[] = {
153     { LVM_INSERTITEM,      sent },
154     { LVM_INSERTITEM,      sent },
155     { LVM_INSERTITEM,      sent },
156     { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
157     { WM_NCPAINT,          sent|optional },
158     { WM_ERASEBKGND,       sent|optional },
159     { LVM_GETITEMPOSITION, sent|wparam,        1 },
160     { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
161     { LVM_GETITEMPOSITION, sent|wparam,        2 },
162     { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
163     { LVM_GETITEMPOSITION, sent|wparam,        0 },
164     { 0 }
165 };
166
167 static const struct message listview_ownerdata_switchto_seq[] = {
168     { WM_STYLECHANGING,    sent },
169     { WM_STYLECHANGED,     sent },
170     { 0 }
171 };
172
173 static const struct message listview_getorderarray_seq[] = {
174     { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
175     { HDM_GETORDERARRAY,       sent|id|wparam, 2, 0, HEADER_ID },
176     { 0 }
177 };
178
179 static const struct message empty_seq[] = {
180     { 0 }
181 };
182
183 static const struct message forward_erasebkgnd_parent_seq[] = {
184     { WM_ERASEBKGND, sent },
185     { 0 }
186 };
187
188 static const struct message ownderdata_select_focus_parent_seq[] = {
189     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
190     { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
191     { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
192     { 0 }
193 };
194
195 static const struct message ownerdata_setstate_all_parent_seq[] = {
196     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
197     { 0 }
198 };
199
200 static const struct message ownerdata_defocus_all_parent_seq[] = {
201     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
202     { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
203     { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
204     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
205     { 0 }
206 };
207
208 static const struct message ownerdata_deselect_all_parent_seq[] = {
209     { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
210     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
211     { 0 }
212 };
213
214 static const struct message change_all_parent_seq[] = {
215     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
216     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
217
218     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
219     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
220
221     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
222     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
223
224     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
225     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
226
227     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
228     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
229     { 0 }
230 };
231
232 static const struct message changing_all_parent_seq[] = {
233     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
234     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
235     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
236     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
237     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
238     { 0 }
239 };
240
241 static const struct message textcallback_set_again_parent_seq[] = {
242     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
243     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED  },
244     { 0 }
245 };
246
247 static const struct message single_getdispinfo_parent_seq[] = {
248     { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
249     { 0 }
250 };
251
252 static const struct message getitemposition_seq1[] = {
253     { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
254     { 0 }
255 };
256
257 static const struct message getitemposition_seq2[] = {
258     { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
259     { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
260     { 0 }
261 };
262
263 static const struct message getsubitemrect_seq[] = {
264     { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
265     { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
266     { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
267     { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
268     { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
269     { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
270     { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
271     { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
272     { 0 }
273 };
274
275 static const struct message editbox_create_pos[] = {
276     /* sequence sent after LVN_BEGINLABELEDIT */
277     /* next two are 4.7x specific */
278     { WM_WINDOWPOSCHANGING, sent },
279     { WM_WINDOWPOSCHANGED, sent|optional },
280
281     { WM_WINDOWPOSCHANGING, sent|optional },
282     { WM_NCCALCSIZE, sent },
283     { WM_WINDOWPOSCHANGED, sent },
284     { WM_MOVE, sent|defwinproc },
285     { WM_SIZE, sent|defwinproc },
286     /* the rest is todo, skipped in 4.7x */
287     { WM_WINDOWPOSCHANGING, sent|optional },
288     { WM_WINDOWPOSCHANGED, sent|optional },
289     { 0 }
290 };
291
292 static const struct message scroll_parent_seq[] = {
293     { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
294     { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
295     { 0 }
296 };
297
298 static const struct message setredraw_seq[] = {
299     { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
300     { 0 }
301 };
302
303 static const struct message lvs_ex_transparentbkgnd_seq[] = {
304     { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
305     { 0 }
306 };
307
308 static const struct message edit_end_nochange[] = {
309     { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
310     { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },     /* todo */
311     { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
312     { 0 }
313 };
314
315 static const struct message hover_parent[] = {
316     { WM_GETDLGCODE, sent }, /* todo_wine */
317     { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
318     { 0 }
319 };
320
321 static const struct message listview_destroy[] = {
322     { 0x0090, sent|optional }, /* Vista */
323     { WM_PARENTNOTIFY, sent },
324     { WM_SHOWWINDOW, sent },
325     { WM_WINDOWPOSCHANGING, sent },
326     { WM_WINDOWPOSCHANGED, sent|optional },
327     { WM_DESTROY, sent },
328     { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
329     { WM_NCDESTROY, sent },
330     { 0 }
331 };
332
333 static const struct message listview_header_changed_seq[] = {
334     { LVM_SETCOLUMNA, sent },
335     { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
336     { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
337     { 0 }
338 };
339
340 static const struct message parent_header_click_seq[] = {
341     { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
342     { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
343     { 0 }
344 };
345
346 static const struct message parent_header_divider_dclick_seq[] = {
347     { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
348     { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
349     { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
350     { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
351     { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
352     { 0 }
353 };
354
355 static const struct message listview_set_imagelist[] = {
356     { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
357     { 0 }
358 };
359
360 static const struct message listview_header_set_imagelist[] = {
361     { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
362     { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
363     { 0 }
364 };
365
366 static const struct message parent_insert_focused_seq[] = {
367     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
368     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
369     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
370     { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
371     { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
372     { 0 }
373 };
374
375 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
376 {
377     static LONG defwndproc_counter = 0;
378     LRESULT ret;
379     struct message msg;
380
381     msg.message = message;
382     msg.flags = sent|wparam|lparam;
383     if (defwndproc_counter) msg.flags |= defwinproc;
384     msg.wParam = wParam;
385     msg.lParam = lParam;
386     if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
387
388     /* log system messages, except for painting */
389     if (message < WM_USER &&
390         message != WM_PAINT &&
391         message != WM_ERASEBKGND &&
392         message != WM_NCPAINT &&
393         message != WM_NCHITTEST &&
394         message != WM_GETTEXT &&
395         message != WM_GETICON &&
396         message != WM_DEVICECHANGE)
397     {
398         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
399
400         add_message(sequences, PARENT_SEQ_INDEX, &msg);
401         add_message(sequences, COMBINED_SEQ_INDEX, &msg);
402     }
403     add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
404
405     switch (message)
406     {
407       case WM_NOTIFY:
408       {
409           switch (((NMHDR*)lParam)->code)
410           {
411           case LVN_BEGINLABELEDIT:
412           {
413               HWND edit = NULL;
414
415               /* subclass edit box */
416               if (!blockEdit)
417                   edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
418
419               if (edit)
420               {
421                   INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
422                   ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
423                       "text limit %d, expected 259\n", len);
424               }
425
426               return blockEdit;
427           }
428           case LVN_ENDLABELEDIT:
429               {
430               HWND edit;
431
432               /* always accept new item text */
433               NMLVDISPINFO *di = (NMLVDISPINFO*)lParam;
434               g_editbox_disp_info = *di;
435               trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText ? di->item.pszText : "(null)");
436
437               /* edit control still available from this notification */
438               edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
439               ok(IsWindow(edit), "expected valid edit control handle\n");
440               ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
441
442               return TRUE;
443               }
444           case LVN_BEGINSCROLL:
445           case LVN_ENDSCROLL:
446               {
447               NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
448
449               trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
450                                                "BEGIN" : "END", pScroll->dx, pScroll->dy);
451               }
452               break;
453           case LVN_ITEMCHANGING:
454               {
455                   NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
456                   g_nmlistview_changing = *nmlv;
457               }
458               break;
459           case LVN_ITEMCHANGED:
460               {
461                   NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
462                   g_nmlistview = *nmlv;
463               }
464               break;
465           case LVN_GETDISPINFOA:
466               {
467                   NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
468                   g_itema = dispinfo->item;
469
470                   if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
471                   {
472                       static const WCHAR testW[] = {'T','E','S','T',0};
473                       dispinfo->hdr.code = LVN_GETDISPINFOW;
474                       memcpy(dispinfo->item.pszText, testW, sizeof(testW));
475                   }
476
477                   /* test control buffer size for text, 10 used to mask cases when control
478                      is using caller buffer to process LVM_GETITEM for example */
479                   if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
480                       ok(dispinfo->item.cchTextMax == 260 ||
481                          broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
482                       "buffer size %d\n", dispinfo->item.cchTextMax);
483               }
484               break;
485           case LVN_DELETEITEM:
486               if (g_focus_test_LVN_DELETEITEM)
487               {
488                   NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
489                   UINT state;
490
491                   state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
492                   ok(state == 0, "got state %x\n", state);
493               }
494               break;
495           case NM_HOVER:
496               if (g_block_hover) return 1;
497               break;
498           }
499           break;
500       }
501       case WM_NOTIFYFORMAT:
502       {
503           /* force to return format */
504           if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
505           break;
506       }
507     }
508
509     defwndproc_counter++;
510     ret = DefWindowProcA(hwnd, message, wParam, lParam);
511     defwndproc_counter--;
512
513     return ret;
514 }
515
516 static BOOL register_parent_wnd_class(BOOL Unicode)
517 {
518     WNDCLASSA clsA;
519     WNDCLASSW clsW;
520
521     if (Unicode)
522     {
523         clsW.style = 0;
524         clsW.lpfnWndProc = parent_wnd_proc;
525         clsW.cbClsExtra = 0;
526         clsW.cbWndExtra = 0;
527         clsW.hInstance = GetModuleHandleW(NULL);
528         clsW.hIcon = 0;
529         clsW.hCursor = LoadCursorA(0, IDC_ARROW);
530         clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
531         clsW.lpszMenuName = NULL;
532         clsW.lpszClassName = testparentclassW;
533     }
534     else
535     {
536         clsA.style = 0;
537         clsA.lpfnWndProc = parent_wnd_proc;
538         clsA.cbClsExtra = 0;
539         clsA.cbWndExtra = 0;
540         clsA.hInstance = GetModuleHandleA(NULL);
541         clsA.hIcon = 0;
542         clsA.hCursor = LoadCursorA(0, IDC_ARROW);
543         clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
544         clsA.lpszMenuName = NULL;
545         clsA.lpszClassName = "Listview test parent class";
546     }
547
548     return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
549 }
550
551 static HWND create_parent_window(BOOL Unicode)
552 {
553     static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
554     HWND hwnd;
555
556     if (!register_parent_wnd_class(Unicode))
557         return NULL;
558
559     blockEdit = FALSE;
560     notifyFormat = -1;
561
562     if (Unicode)
563         hwnd = CreateWindowExW(0, testparentclassW, nameW,
564                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
565                                WS_MAXIMIZEBOX | WS_VISIBLE,
566                                0, 0, 100, 100,
567                                GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
568     else
569         hwnd = CreateWindowExA(0, "Listview test parent class",
570                                "Listview test parent window",
571                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
572                                WS_MAXIMIZEBOX | WS_VISIBLE,
573                                0, 0, 100, 100,
574                                GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
575     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
576     return hwnd;
577 }
578
579 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
580 {
581     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
582     static LONG defwndproc_counter = 0;
583     LRESULT ret;
584     struct message msg;
585
586     trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
587
588     /* some debug output for style changing */
589     if ((message == WM_STYLECHANGING ||
590          message == WM_STYLECHANGED) && lParam)
591     {
592         STYLESTRUCT *style = (STYLESTRUCT*)lParam;
593         trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
594     }
595
596     msg.message = message;
597     msg.flags = sent|wparam|lparam;
598     if (defwndproc_counter) msg.flags |= defwinproc;
599     msg.wParam = wParam;
600     msg.lParam = lParam;
601     msg.id = LISTVIEW_ID;
602     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
603     add_message(sequences, COMBINED_SEQ_INDEX, &msg);
604
605     defwndproc_counter++;
606     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
607     defwndproc_counter--;
608     return ret;
609 }
610
611 static HWND create_listview_control(DWORD style)
612 {
613     WNDPROC oldproc;
614     HWND hwnd;
615     RECT rect;
616
617     GetClientRect(hwndparent, &rect);
618     hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
619                            WS_CHILD | WS_BORDER | WS_VISIBLE | style,
620                            0, 0, rect.right, rect.bottom,
621                            hwndparent, NULL, GetModuleHandleA(NULL), NULL);
622     ok(hwnd != NULL, "gle=%d\n", GetLastError());
623
624     if (!hwnd) return NULL;
625
626     oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
627                                         (LONG_PTR)listview_subclass_proc);
628     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
629
630     return hwnd;
631 }
632
633 /* unicode listview window with specified parent */
634 static HWND create_listview_controlW(DWORD style, HWND parent)
635 {
636     WNDPROC oldproc;
637     HWND hwnd;
638     RECT rect;
639     static const WCHAR nameW[] = {'f','o','o',0};
640
641     GetClientRect(parent, &rect);
642     hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
643                            WS_CHILD | WS_BORDER | WS_VISIBLE | style,
644                            0, 0, rect.right, rect.bottom,
645                            parent, NULL, GetModuleHandleW(NULL), NULL);
646     ok(hwnd != NULL, "gle=%d\n", GetLastError());
647
648     if (!hwnd) return NULL;
649
650     oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
651                                         (LONG_PTR)listview_subclass_proc);
652     SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
653
654     return hwnd;
655 }
656
657 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
658 {
659     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
660     static LONG defwndproc_counter = 0;
661     LRESULT ret;
662     struct message msg;
663
664     trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
665
666     msg.message = message;
667     msg.flags = sent|wparam|lparam;
668     if (defwndproc_counter) msg.flags |= defwinproc;
669     msg.wParam = wParam;
670     msg.lParam = lParam;
671     msg.id = HEADER_ID;
672     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
673
674     defwndproc_counter++;
675     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
676     defwndproc_counter--;
677     return ret;
678 }
679
680 static HWND subclass_header(HWND hwndListview)
681 {
682     WNDPROC oldproc;
683     HWND hwnd;
684
685     hwnd = ListView_GetHeader(hwndListview);
686     oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
687                                          (LONG_PTR)header_subclass_proc);
688     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
689
690     return hwnd;
691 }
692
693 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
694 {
695     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
696     static LONG defwndproc_counter = 0;
697     LRESULT ret;
698     struct message msg;
699
700     msg.message = message;
701     msg.flags = sent|wparam|lparam;
702     if (defwndproc_counter) msg.flags |= defwinproc;
703     msg.wParam = wParam;
704     msg.lParam = lParam;
705     msg.id = 0;
706
707     /* all we need is sizing */
708     if (message == WM_WINDOWPOSCHANGING ||
709         message == WM_NCCALCSIZE ||
710         message == WM_WINDOWPOSCHANGED ||
711         message == WM_MOVE ||
712         message == WM_SIZE)
713     {
714         add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
715     }
716
717     defwndproc_counter++;
718     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
719     defwndproc_counter--;
720     return ret;
721 }
722
723 static HWND subclass_editbox(HWND hwndListview)
724 {
725     WNDPROC oldproc;
726     HWND hwnd;
727
728     hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0);
729     oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
730                                          (LONG_PTR)editbox_subclass_proc);
731     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
732
733     return hwnd;
734 }
735
736 /* Performs a single LVM_HITTEST test */
737 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
738                               BOOL todo_item, BOOL todo_flags, int line)
739 {
740     LVHITTESTINFO lpht;
741     INT ret;
742
743     lpht.pt.x = x;
744     lpht.pt.y = y;
745     lpht.iSubItem = 10;
746
747     ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
748
749     if (todo_item)
750     {
751         todo_wine
752         {
753             ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
754             ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
755             ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
756         }
757     }
758     else
759     {
760         ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
761         ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
762         ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
763     }
764
765     if (todo_flags)
766     {
767         todo_wine
768             ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
769     }
770     else if (broken_flags)
771         ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
772                             "Expected flags %x, got %x\n", flags, lpht.flags);
773     else
774         ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
775 }
776
777 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
778
779 /* Performs a single LVM_SUBITEMHITTEST test */
780 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
781                                      BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
782 {
783     LVHITTESTINFO lpht;
784     INT ret;
785
786     lpht.pt.x = x;
787     lpht.pt.y = y;
788
789     ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
790
791     if (todo_item)
792     {
793         todo_wine
794         {
795             ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
796             ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
797         }
798     }
799     else
800     {
801         ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
802         ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
803     }
804
805     if (todo_subitem)
806     {
807         todo_wine
808             ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
809     }
810     else
811         ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
812
813     if (todo_flags)
814     {
815         todo_wine
816             ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
817     }
818     else
819         ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
820 }
821
822 #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__)
823
824 static void test_images(void)
825 {
826     HWND hwnd;
827     INT r;
828     LVITEM item;
829     HIMAGELIST himl;
830     HBITMAP hbmp;
831     RECT r1, r2;
832     static CHAR hello[] = "hello";
833
834     himl = ImageList_Create(40, 40, 0, 4, 4);
835     ok(himl != NULL, "failed to create imagelist\n");
836
837     hbmp = CreateBitmap(40, 40, 1, 1, NULL);
838     ok(hbmp != NULL, "failed to create bitmap\n");
839
840     r = ImageList_Add(himl, hbmp, 0);
841     ok(r == 0, "should be zero\n");
842
843     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 
844                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
845     ok(hwnd != NULL, "failed to create listview window\n");
846
847     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
848                     LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
849
850     ok(r == 0, "should return zero\n");
851
852     r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
853     ok(r == 0, "should return zero\n");
854
855     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
856     ok(r != 0, "got 0\n");
857
858     /* returns dimensions */
859
860     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
861     ok(r == 0, "should be zero items\n");
862
863     item.mask = LVIF_IMAGE | LVIF_TEXT;
864     item.iItem = 0;
865     item.iSubItem = 1;
866     item.iImage = 0;
867     item.pszText = 0;
868     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
869     ok(r == -1, "should fail\n");
870
871     item.iSubItem = 0;
872     item.pszText = hello;
873     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
874     ok(r == 0, "should not fail\n");
875
876     memset(&r1, 0, sizeof r1);
877     r1.left = LVIR_ICON;
878     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
879     expect(1, r);
880
881     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
882     ok(r == TRUE, "should not fail\n");
883
884     item.iSubItem = 0;
885     item.pszText = hello;
886     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
887     ok(r == 0, "should not fail\n");
888
889     memset(&r2, 0, sizeof r2);
890     r2.left = LVIR_ICON;
891     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
892     expect(1, r);
893
894     ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
895
896     DestroyWindow(hwnd);
897 }
898
899 static void test_checkboxes(void)
900 {
901     HWND hwnd;
902     LVITEMA item;
903     DWORD r;
904     static CHAR text[]  = "Text",
905                 text2[] = "Text2",
906                 text3[] = "Text3";
907
908     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 
909                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
910     ok(hwnd != NULL, "failed to create listview window\n");
911
912     /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
913     item.mask = LVIF_TEXT | LVIF_STATE;
914     item.stateMask = 0xffff;
915     item.state = 0xfccc;
916     item.iItem = 0;
917     item.iSubItem = 0;
918     item.pszText = text;
919     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
920     expect(0, r);
921
922     item.iItem = 0;
923     item.mask = LVIF_STATE;
924     item.stateMask = 0xffff;
925     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
926     expect(1, r);
927     ok(item.state == 0xfccc, "state %x\n", item.state);
928
929     /* Don't set LVIF_STATE */
930     item.mask = LVIF_TEXT;
931     item.stateMask = 0xffff;
932     item.state = 0xfccc;
933     item.iItem = 1;
934     item.iSubItem = 0;
935     item.pszText = text;
936     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
937     expect(1, r);
938
939     item.iItem = 1;
940     item.mask = LVIF_STATE;
941     item.stateMask = 0xffff;
942     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
943     expect(1, r);
944     ok(item.state == 0, "state %x\n", item.state);
945
946     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
947     expect(0, r);
948
949     /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
950     item.iItem = 0;
951     item.mask = LVIF_STATE;
952     item.stateMask = 0xffff;
953     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
954     expect(1, r);
955     if (item.state != 0x1ccc)
956     {
957         win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
958         DestroyWindow(hwnd);
959         return;
960     }
961
962     /* Now add an item without specifying a state and check that its state goes to 0x1000 */
963     item.iItem = 2;
964     item.mask = LVIF_TEXT;
965     item.state = 0;
966     item.pszText = text2;
967     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
968     expect(2, r);
969
970     item.iItem = 2;
971     item.mask = LVIF_STATE;
972     item.stateMask = 0xffff;
973     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
974     expect(1, r);
975     ok(item.state == 0x1000, "state %x\n", item.state);
976
977     /* Add a further item this time specifying a state and still its state goes to 0x1000 */
978     item.iItem = 3;
979     item.mask = LVIF_TEXT | LVIF_STATE;
980     item.stateMask = 0xffff;
981     item.state = 0x2aaa;
982     item.pszText = text3;
983     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
984     expect(3, r);
985
986     item.iItem = 3;
987     item.mask = LVIF_STATE;
988     item.stateMask = 0xffff;
989     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
990     expect(1, r);
991     ok(item.state == 0x1aaa, "state %x\n", item.state);
992
993     /* Set an item's state to checked */
994     item.iItem = 3;
995     item.mask = LVIF_STATE;
996     item.stateMask = 0xf000;
997     item.state = 0x2000;
998     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
999     expect(1, r);
1000
1001     item.iItem = 3;
1002     item.mask = LVIF_STATE;
1003     item.stateMask = 0xffff;
1004     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1005     expect(1, r);
1006     ok(item.state == 0x2aaa, "state %x\n", item.state);
1007
1008     /* Check that only the bits we asked for are returned,
1009      * and that all the others are set to zero
1010      */
1011     item.iItem = 3;
1012     item.mask = LVIF_STATE;
1013     item.stateMask = 0xf000;
1014     item.state = 0xffff;
1015     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1016     expect(1, r);
1017     ok(item.state == 0x2000, "state %x\n", item.state);
1018
1019     /* Set the style again and check that doesn't change an item's state */
1020     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1021     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1022
1023     item.iItem = 3;
1024     item.mask = LVIF_STATE;
1025     item.stateMask = 0xffff;
1026     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1027     expect(1, r);
1028     ok(item.state == 0x2aaa, "state %x\n", item.state);
1029
1030     /* Unsetting the checkbox extended style doesn't change an item's state */
1031     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1032     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1033
1034     item.iItem = 3;
1035     item.mask = LVIF_STATE;
1036     item.stateMask = 0xffff;
1037     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1038     expect(1, r);
1039     ok(item.state == 0x2aaa, "state %x\n", item.state);
1040
1041     /* Now setting the style again will change an item's state */
1042     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1043     expect(0, r);
1044
1045     item.iItem = 3;
1046     item.mask = LVIF_STATE;
1047     item.stateMask = 0xffff;
1048     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1049     expect(1, r);
1050     ok(item.state == 0x1aaa, "state %x\n", item.state);
1051
1052     /* Toggle checkbox tests (bug 9934) */
1053     memset (&item, 0xcc, sizeof(item));
1054     item.mask = LVIF_STATE;
1055     item.iItem = 3;
1056     item.iSubItem = 0;
1057     item.state = LVIS_FOCUSED;
1058     item.stateMask = LVIS_FOCUSED;
1059     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1060     expect(1, r);
1061
1062     item.iItem = 3;
1063     item.mask = LVIF_STATE;
1064     item.stateMask = 0xffff;
1065     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1066     expect(1, r);
1067     ok(item.state == 0x1aab, "state %x\n", item.state);
1068
1069     r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1070     expect(0, r);
1071     r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
1072     expect(0, r);
1073
1074     item.iItem = 3;
1075     item.mask = LVIF_STATE;
1076     item.stateMask = 0xffff;
1077     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1078     expect(1, r);
1079     ok(item.state == 0x2aab, "state %x\n", item.state);
1080
1081     r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1082     expect(0, r);
1083     r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
1084     expect(0, r);
1085
1086     item.iItem = 3;
1087     item.mask = LVIF_STATE;
1088     item.stateMask = 0xffff;
1089     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1090     expect(1, r);
1091     ok(item.state == 0x1aab, "state %x\n", item.state);
1092
1093     DestroyWindow(hwnd);
1094 }
1095
1096 static void insert_column(HWND hwnd, int idx)
1097 {
1098     LVCOLUMN column;
1099     INT rc;
1100
1101     memset(&column, 0xcc, sizeof(column));
1102     column.mask = LVCF_SUBITEM;
1103     column.iSubItem = idx;
1104
1105     rc = ListView_InsertColumn(hwnd, idx, &column);
1106     expect(idx, rc);
1107 }
1108
1109 static void insert_item(HWND hwnd, int idx)
1110 {
1111     static CHAR text[] = "foo";
1112
1113     LVITEMA item;
1114     INT rc;
1115
1116     memset(&item, 0xcc, sizeof (item));
1117     item.mask = LVIF_TEXT;
1118     item.iItem = idx;
1119     item.iSubItem = 0;
1120     item.pszText = text;
1121
1122     rc = ListView_InsertItem(hwnd, &item);
1123     expect(idx, rc);
1124 }
1125
1126 static void test_items(void)
1127 {
1128     const LPARAM lparamTest = 0x42;
1129     static CHAR text[] = "Text";
1130     char buffA[5];
1131     HWND hwnd;
1132     LVITEMA item;
1133     DWORD r;
1134
1135     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
1136                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1137     ok(hwnd != NULL, "failed to create listview window\n");
1138
1139     /*
1140      * Test setting/getting item params
1141      */
1142
1143     /* Set up two columns */
1144     insert_column(hwnd, 0);
1145     insert_column(hwnd, 1);
1146
1147     /* LVIS_SELECTED with zero stateMask */
1148     /* set */
1149     memset (&item, 0, sizeof (item));
1150     item.mask = LVIF_STATE;
1151     item.state = LVIS_SELECTED;
1152     item.stateMask = 0;
1153     item.iItem = 0;
1154     item.iSubItem = 0;
1155     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1156     expect(0, r);
1157     /* get */
1158     memset (&item, 0xcc, sizeof (item));
1159     item.mask = LVIF_STATE;
1160     item.stateMask = LVIS_SELECTED;
1161     item.state = 0;
1162     item.iItem = 0;
1163     item.iSubItem = 0;
1164     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1165     expect(1, r);
1166     ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1167     SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1168
1169     /* LVIS_SELECTED with zero stateMask */
1170     /* set */
1171     memset (&item, 0, sizeof (item));
1172     item.mask = LVIF_STATE;
1173     item.state = LVIS_FOCUSED;
1174     item.stateMask = 0;
1175     item.iItem = 0;
1176     item.iSubItem = 0;
1177     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1178     expect(0, r);
1179     /* get */
1180     memset (&item, 0xcc, sizeof (item));
1181     item.mask = LVIF_STATE;
1182     item.stateMask = LVIS_FOCUSED;
1183     item.state = 0;
1184     item.iItem = 0;
1185     item.iSubItem = 0;
1186     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1187     expect(1, r);
1188     ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1189     SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1190
1191     /* LVIS_CUT with LVIS_FOCUSED stateMask */
1192     /* set */
1193     memset (&item, 0, sizeof (item));
1194     item.mask = LVIF_STATE;
1195     item.state = LVIS_CUT;
1196     item.stateMask = LVIS_FOCUSED;
1197     item.iItem = 0;
1198     item.iSubItem = 0;
1199     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1200     expect(0, r);
1201     /* get */
1202     memset (&item, 0xcc, sizeof (item));
1203     item.mask = LVIF_STATE;
1204     item.stateMask = LVIS_CUT;
1205     item.state = 0;
1206     item.iItem = 0;
1207     item.iSubItem = 0;
1208     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1209     expect(1, r);
1210     ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1211     SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1212
1213     /* Insert an item with just a param */
1214     memset (&item, 0xcc, sizeof (item));
1215     item.mask = LVIF_PARAM;
1216     item.iItem = 0;
1217     item.iSubItem = 0;
1218     item.lParam = lparamTest;
1219     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1220     expect(0, r);
1221
1222     /* Test getting of the param */
1223     memset (&item, 0xcc, sizeof (item));
1224     item.mask = LVIF_PARAM;
1225     item.iItem = 0;
1226     item.iSubItem = 0;
1227     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1228     expect(1, r);
1229     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1230
1231     /* Set up a subitem */
1232     memset (&item, 0xcc, sizeof (item));
1233     item.mask = LVIF_TEXT;
1234     item.iItem = 0;
1235     item.iSubItem = 1;
1236     item.pszText = text;
1237     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1238     expect(1, r);
1239
1240     item.mask = LVIF_TEXT;
1241     item.iItem = 0;
1242     item.iSubItem = 1;
1243     item.pszText = buffA;
1244     item.cchTextMax = sizeof(buffA);
1245     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1246     expect(1, r);
1247     ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1248
1249     /* set up with extra flag */
1250     /* 1. reset subitem text */
1251     item.mask = LVIF_TEXT;
1252     item.iItem = 0;
1253     item.iSubItem = 1;
1254     item.pszText = NULL;
1255     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1256     expect(1, r);
1257
1258     item.mask = LVIF_TEXT;
1259     item.iItem = 0;
1260     item.iSubItem = 1;
1261     item.pszText = buffA;
1262     buffA[0] = 'a';
1263     item.cchTextMax = sizeof(buffA);
1264     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1265     expect(1, r);
1266     ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1267
1268     /* 2. set new text with extra flag specified */
1269     item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1270     item.iItem = 0;
1271     item.iSubItem = 1;
1272     item.pszText = text;
1273     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1274     ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1275
1276     if (r == 1)
1277     {
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 = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1285         expect(1, r);
1286         ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1287     }
1288
1289     /* Query param from subitem: returns main item param */
1290     memset (&item, 0xcc, sizeof (item));
1291     item.mask = LVIF_PARAM;
1292     item.iItem = 0;
1293     item.iSubItem = 1;
1294     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1295     expect(1, r);
1296     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1297
1298     /* Set up param on first subitem: no effect */
1299     memset (&item, 0xcc, sizeof (item));
1300     item.mask = LVIF_PARAM;
1301     item.iItem = 0;
1302     item.iSubItem = 1;
1303     item.lParam = lparamTest+1;
1304     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1305     expect(0, r);
1306
1307     /* Query param from subitem again: should still return main item param */
1308     memset (&item, 0xcc, sizeof (item));
1309     item.mask = LVIF_PARAM;
1310     item.iItem = 0;
1311     item.iSubItem = 1;
1312     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1313     expect(1, r);
1314     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1315
1316     /**** Some tests of state highlighting ****/
1317     memset (&item, 0xcc, sizeof (item));
1318     item.mask = LVIF_STATE;
1319     item.iItem = 0;
1320     item.iSubItem = 0;
1321     item.state = LVIS_SELECTED;
1322     item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1323     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1324     expect(1, r);
1325     item.iSubItem = 1;
1326     item.state = LVIS_DROPHILITED;
1327     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1328     expect(1, r);
1329
1330     memset (&item, 0xcc, sizeof (item));
1331     item.mask = LVIF_STATE;
1332     item.iItem = 0;
1333     item.iSubItem = 0;
1334     item.stateMask = -1;
1335     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1336     expect(1, r);
1337     ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1338     item.iSubItem = 1;
1339     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1340     expect(1, r);
1341     todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1342
1343     /* some notnull but meaningless masks */
1344     memset (&item, 0, sizeof(item));
1345     item.mask = LVIF_NORECOMPUTE;
1346     item.iItem = 0;
1347     item.iSubItem = 0;
1348     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1349     expect(1, r);
1350     memset (&item, 0, sizeof(item));
1351     item.mask = LVIF_DI_SETITEM;
1352     item.iItem = 0;
1353     item.iSubItem = 0;
1354     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1355     expect(1, r);
1356
1357     /* set text to callback value already having it */
1358     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1359     expect(TRUE, r);
1360     memset (&item, 0, sizeof (item));
1361     item.mask  = LVIF_TEXT;
1362     item.pszText = LPSTR_TEXTCALLBACK;
1363     item.iItem = 0;
1364     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1365     expect(0, r);
1366     memset (&item, 0, sizeof (item));
1367
1368     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1369
1370     item.pszText = LPSTR_TEXTCALLBACK;
1371     r = SendMessage(hwnd, LVM_SETITEMTEXT, 0 , (LPARAM) &item);
1372     expect(TRUE, r);
1373
1374     ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1375                 "check callback text comparison rule", FALSE);
1376
1377     DestroyWindow(hwnd);
1378 }
1379
1380 static void test_columns(void)
1381 {
1382     HWND hwnd;
1383     LVCOLUMNA column;
1384     LVITEMA item;
1385     INT order[2];
1386     CHAR buff[5];
1387     DWORD rc;
1388
1389     hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT,
1390                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1391     ok(hwnd != NULL, "failed to create listview window\n");
1392
1393     /* Add a column with no mask */
1394     memset(&column, 0xcc, sizeof(column));
1395     column.mask = 0;
1396     rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1397     ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1398
1399     /* Check its width */
1400     rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1401     ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1402
1403     DestroyWindow(hwnd);
1404
1405     /* LVM_GETCOLUMNORDERARRAY */
1406     hwnd = create_listview_control(LVS_REPORT);
1407     subclass_header(hwnd);
1408
1409     memset(&column, 0, sizeof(column));
1410     column.mask = LVCF_WIDTH;
1411     column.cx = 100;
1412     rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1413     expect(0, rc);
1414
1415     column.cx = 200;
1416     rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1417     expect(1, rc);
1418
1419     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1420
1421     rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1422     expect(1, rc);
1423     ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1424     ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1425
1426     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1427
1428     /* after column added subitem is considered as present */
1429     insert_item(hwnd, 0);
1430
1431     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1432
1433     item.pszText = buff;
1434     item.cchTextMax = sizeof(buff);
1435     item.iItem = 0;
1436     item.iSubItem = 1;
1437     item.mask = LVIF_TEXT;
1438     memset(&g_itema, 0, sizeof(g_itema));
1439     rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1440     expect(1, rc);
1441     ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1442
1443     ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1444         "get subitem text after column added", FALSE);
1445
1446     DestroyWindow(hwnd);
1447 }
1448
1449 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1450 static WNDPROC listviewWndProc;
1451 static HIMAGELIST test_create_imagelist;
1452
1453 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1454 {
1455     LRESULT ret;
1456
1457     if (uMsg == WM_CREATE)
1458     {
1459         LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
1460         lpcs->style |= LVS_REPORT;
1461     }
1462     ret = CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
1463     if (uMsg == WM_CREATE) SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1464     return ret;
1465 }
1466
1467 static void test_create(void)
1468 {
1469     HWND hList;
1470     HWND hHeader;
1471     LONG_PTR ret;
1472     LONG r;
1473     LVCOLUMNA col;
1474     RECT rect;
1475     WNDCLASSEX cls;
1476     DWORD style;
1477
1478     cls.cbSize = sizeof(WNDCLASSEX);
1479     ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1480     listviewWndProc = cls.lpfnWndProc;
1481     cls.lpfnWndProc = create_test_wndproc;
1482     cls.lpszClassName = "MyListView32";
1483     ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
1484
1485     test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1486     hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1487     ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1488     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1489
1490     if (!IsWindow(hHeader))
1491     {
1492         /* version 4.0 */
1493         win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1494         DestroyWindow(hList);
1495         return;
1496     }
1497
1498     ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1499     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1500     DestroyWindow(hList);
1501
1502     /* header isn't created on LVS_ICON and LVS_LIST styles */
1503     hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1504                           GetModuleHandle(NULL), 0);
1505     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1506     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1507     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1508     /* insert column */
1509     memset(&col, 0, sizeof(LVCOLUMNA));
1510     col.mask = LVCF_WIDTH;
1511     col.cx = 100;
1512     r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1513     expect(0, r);
1514     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1515     ok(IsWindow(hHeader), "Header should be created\n");
1516     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1517     style = GetWindowLong(hHeader, GWL_STYLE);
1518     ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1519     DestroyWindow(hList);
1520
1521     hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1522                           GetModuleHandle(NULL), 0);
1523     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1524     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1525     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1526     /* insert column */
1527     memset(&col, 0, sizeof(LVCOLUMNA));
1528     col.mask = LVCF_WIDTH;
1529     col.cx = 100;
1530     r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1531     expect(0, r);
1532     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1533     ok(IsWindow(hHeader), "Header should be created\n");
1534     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1535     DestroyWindow(hList);
1536
1537     /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1538     hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1539                           GetModuleHandle(NULL), 0);
1540     ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLongPtr(hList, GWL_STYLE) | LVS_REPORT);
1541     ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1542     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1543     ok(IsWindow(hHeader), "Header should be created\n");
1544     ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLong(hList, GWL_STYLE) & ~LVS_REPORT);
1545     ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1546     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1547     ok(IsWindow(hHeader), "Header should be created\n");
1548     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1549     DestroyWindow(hList);
1550
1551     /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1552     hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1553                           GetModuleHandle(NULL), 0);
1554     ret = SetWindowLongPtr(hList, GWL_STYLE,
1555                           (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1556     ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1557     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1558     ok(IsWindow(hHeader), "Header should be created\n");
1559     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1560     ret = SetWindowLongPtr(hList, GWL_STYLE,
1561                           (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1562     ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1563     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1564     ok(IsWindow(hHeader), "Header should be created\n");
1565     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1566     DestroyWindow(hList);
1567
1568     /* LVS_REPORT without WS_VISIBLE */
1569     hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1570                           GetModuleHandle(NULL), 0);
1571     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1572     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1573     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1574     /* insert column */
1575     memset(&col, 0, sizeof(LVCOLUMNA));
1576     col.mask = LVCF_WIDTH;
1577     col.cx = 100;
1578     r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1579     expect(0, r);
1580     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1581     ok(IsWindow(hHeader), "Header should be created\n");
1582     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1583     DestroyWindow(hList);
1584
1585     /* LVS_REPORT without WS_VISIBLE, try to show it */
1586     hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1587                           GetModuleHandle(NULL), 0);
1588     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1589     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1590     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1591     ShowWindow(hList, SW_SHOW);
1592     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1593     ok(IsWindow(hHeader), "Header should be created\n");
1594     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1595     DestroyWindow(hList);
1596
1597     /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1598     hList = CreateWindow("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1599                           0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1600     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1601     ok(IsWindow(hHeader), "Header should be created\n");
1602     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1603     /* HDS_DRAGDROP set by default */
1604     ok(GetWindowLongPtr(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1605     DestroyWindow(hList);
1606
1607     /* setting LVS_EX_HEADERDRAGDROP creates header */
1608     hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1609                           GetModuleHandle(NULL), 0);
1610     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1611     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1612     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1613     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1614     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1615     ok(IsWindow(hHeader) ||
1616        broken(!IsWindow(hHeader)), /* 4.7x common controls */
1617        "Header should be created\n");
1618     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1619     DestroyWindow(hList);
1620
1621     /* setting LVS_EX_GRIDLINES creates header */
1622     hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1623                           GetModuleHandle(NULL), 0);
1624     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1625     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1626     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1627     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1628     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1629     ok(IsWindow(hHeader) ||
1630        broken(!IsWindow(hHeader)), /* 4.7x common controls */
1631        "Header should be created\n");
1632     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1633     DestroyWindow(hList);
1634
1635     /* setting LVS_EX_FULLROWSELECT creates header */
1636     hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1637                           GetModuleHandle(NULL), 0);
1638     hHeader = (HWND)SendMessage(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     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1642     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1643     ok(IsWindow(hHeader) ||
1644        broken(!IsWindow(hHeader)), /* 4.7x common controls */
1645        "Header should be created\n");
1646     ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1647     DestroyWindow(hList);
1648
1649     /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1650     hList = create_listview_control(LVS_ICON);
1651     SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1652     r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1653     ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1654     DestroyWindow(hList);
1655
1656     /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1657     hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1658                           GetModuleHandle(NULL), 0);
1659     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1660     ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1661
1662     rect.left = LVIR_BOUNDS;
1663     rect.top  = 1;
1664     rect.right = rect.bottom = -10;
1665     r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1666     /* right value contains garbage, probably because header columns are not set up */
1667     expect(0, rect.bottom);
1668     expect(1, r);
1669
1670     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1671     ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1672     ok(GetDlgItem(hList, 0) == NULL, "NULL dialog item expected\n");
1673
1674     DestroyWindow(hList);
1675
1676     /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1677     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1678     hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1679     ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1680                 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1681     DestroyWindow(hList);
1682 }
1683
1684 static void test_redraw(void)
1685 {
1686     HWND hwnd;
1687     HDC hdc;
1688     BOOL res;
1689     DWORD r;
1690
1691     hwnd = create_listview_control(LVS_REPORT);
1692     subclass_header(hwnd);
1693
1694     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1695
1696     InvalidateRect(hwnd, NULL, TRUE);
1697     UpdateWindow(hwnd);
1698     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1699
1700     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1701
1702     /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1703     /* 1. Without backbuffer */
1704     res = ListView_SetBkColor(hwnd, CLR_NONE);
1705     expect(TRUE, res);
1706
1707     hdc = GetWindowDC(hwndparent);
1708
1709     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1710     r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1711     ok(r == 1, "Expected not zero result\n");
1712     ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1713                 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1714
1715     res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1716     expect(TRUE, res);
1717
1718     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1719     r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1720     expect(1, r);
1721     ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1722                 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1723
1724     /* 2. With backbuffer */
1725     SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1726                                                      LVS_EX_DOUBLEBUFFER);
1727     res = ListView_SetBkColor(hwnd, CLR_NONE);
1728     expect(TRUE, res);
1729
1730     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1731     r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1732     expect(1, r);
1733     ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1734                 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1735
1736     res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1737     expect(TRUE, res);
1738
1739     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1740     r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1741     todo_wine expect(1, r);
1742     ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1743                 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1744
1745     ReleaseDC(hwndparent, hdc);
1746
1747     DestroyWindow(hwnd);
1748 }
1749
1750 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1751 {
1752     COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1753
1754     if(msg == WM_NOTIFY) {
1755         NMHDR *nmhdr = (PVOID)lp;
1756         if(nmhdr->code == NM_CUSTOMDRAW) {
1757             NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
1758             trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
1759             switch(nmlvcd->nmcd.dwDrawStage) {
1760             case CDDS_PREPAINT:
1761                 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1762                 return CDRF_NOTIFYITEMDRAW;
1763             case CDDS_ITEMPREPAINT:
1764                 nmlvcd->clrTextBk = CLR_DEFAULT;
1765                 return CDRF_NOTIFYSUBITEMDRAW;
1766             case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1767                 clr = GetBkColor(nmlvcd->nmcd.hdc);
1768                 if (nmlvcd->iSubItem)
1769                     todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1770                 else
1771                     ok(clr == c0ffee, "clr=%.8x\n", clr);
1772                 return CDRF_NOTIFYPOSTPAINT;
1773             case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1774                 clr = GetBkColor(nmlvcd->nmcd.hdc);
1775                 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1776                 return CDRF_DODEFAULT;
1777             }
1778             return CDRF_DODEFAULT;
1779         }
1780     }
1781
1782     return DefWindowProcA(hwnd, msg, wp, lp);
1783 }
1784
1785 static void test_customdraw(void)
1786 {
1787     HWND hwnd;
1788     WNDPROC oldwndproc;
1789
1790     hwnd = create_listview_control(LVS_REPORT);
1791
1792     insert_column(hwnd, 0);
1793     insert_column(hwnd, 1);
1794     insert_item(hwnd, 0);
1795
1796     oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
1797                                            (LONG_PTR)cd_wndproc);
1798
1799     InvalidateRect(hwnd, NULL, TRUE);
1800     UpdateWindow(hwnd);
1801
1802     SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1803
1804     DestroyWindow(hwnd);
1805 }
1806
1807 static void test_icon_spacing(void)
1808 {
1809     /* LVM_SETICONSPACING */
1810     /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1811
1812     HWND hwnd;
1813     WORD w, h;
1814     INT r;
1815
1816     hwnd = create_listview_control(LVS_ICON);
1817     ok(hwnd != NULL, "failed to create a listview window\n");
1818
1819     r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1820     expect(NFR_ANSI, r);
1821
1822     /* reset the icon spacing to defaults */
1823     SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1824
1825     /* now we can request what the defaults are */
1826     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1827     w = LOWORD(r);
1828     h = HIWORD(r);
1829
1830     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1831
1832     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1833     ok(r == MAKELONG(w, h) ||
1834        broken(r == MAKELONG(w, w)), /* win98 */
1835        "Expected %d, got %d\n", MAKELONG(w, h), r);
1836
1837     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1838     if (r == 0)
1839     {
1840         /* version 4.0 */
1841         win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1842         DestroyWindow(hwnd);
1843         return;
1844     }
1845     expect(MAKELONG(20,30), r);
1846
1847     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1848     expect(MAKELONG(25,35), r);
1849
1850     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1851
1852     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1853     DestroyWindow(hwnd);
1854 }
1855
1856 static void test_color(void)
1857 {
1858     RECT rect;
1859     HWND hwnd;
1860     DWORD r;
1861     int i;
1862
1863     COLORREF color;
1864     COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1865
1866     hwnd = create_listview_control(LVS_REPORT);
1867     ok(hwnd != NULL, "failed to create a listview window\n");
1868
1869     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1870
1871     for (i = 0; i < 4; i++)
1872     {
1873         color = colors[i];
1874
1875         r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
1876         expect(TRUE, r);
1877         r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
1878         expect(color, r);
1879
1880         r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
1881         expect (TRUE, r);
1882         r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, 0);
1883         expect(color, r);
1884
1885         r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1886         expect(TRUE, r);
1887         r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
1888         expect(color, r);
1889     }
1890
1891     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1892     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1893
1894     /* invalidation test done separately to avoid a message chain mess */
1895     r = ValidateRect(hwnd, NULL);
1896     expect(TRUE, r);
1897     r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
1898     expect(TRUE, r);
1899
1900     rect.right = rect.bottom = 1;
1901     r = GetUpdateRect(hwnd, &rect, TRUE);
1902     todo_wine expect(FALSE, r);
1903     ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1904
1905     r = ValidateRect(hwnd, NULL);
1906     expect(TRUE, r);
1907     r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
1908     expect(TRUE, r);
1909
1910     rect.right = rect.bottom = 1;
1911     r = GetUpdateRect(hwnd, &rect, TRUE);
1912     todo_wine expect(FALSE, r);
1913     ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1914
1915     r = ValidateRect(hwnd, NULL);
1916     expect(TRUE, r);
1917     r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
1918     expect(TRUE, r);
1919
1920     rect.right = rect.bottom = 1;
1921     r = GetUpdateRect(hwnd, &rect, TRUE);
1922     todo_wine expect(FALSE, r);
1923     ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
1924
1925     DestroyWindow(hwnd);
1926 }
1927
1928 static void test_item_count(void)
1929 {
1930     /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1931
1932     HWND hwnd;
1933     DWORD r;
1934     HDC hdc;
1935     HFONT hOldFont;
1936     TEXTMETRICA tm;
1937     RECT rect;
1938     INT height;
1939
1940     LVITEM item0;
1941     LVITEM item1;
1942     LVITEM item2;
1943     static CHAR item0text[] = "item0";
1944     static CHAR item1text[] = "item1";
1945     static CHAR item2text[] = "item2";
1946
1947     hwnd = create_listview_control(LVS_REPORT);
1948     ok(hwnd != NULL, "failed to create a listview window\n");
1949
1950     /* resize in dpiaware manner to fit all 3 items added */
1951     hdc = GetDC(0);
1952     hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
1953     GetTextMetricsA(hdc, &tm);
1954     /* 2 extra pixels for bounds and header border */
1955     height = tm.tmHeight + 2;
1956     SelectObject(hdc, hOldFont);
1957     ReleaseDC(0, hdc);
1958
1959     GetWindowRect(hwnd, &rect);
1960     /* 3 items + 1 header + 1 to be sure */
1961     MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
1962
1963     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1964
1965     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1966     expect(0, r);
1967
1968     /* [item0] */
1969     item0.mask = LVIF_TEXT;
1970     item0.iItem = 0;
1971     item0.iSubItem = 0;
1972     item0.pszText = item0text;
1973     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1974     expect(0, r);
1975
1976     /* [item0, item1] */
1977     item1.mask = LVIF_TEXT;
1978     item1.iItem = 1;
1979     item1.iSubItem = 0;
1980     item1.pszText = item1text;
1981     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1982     expect(1, r);
1983
1984     /* [item0, item1, item2] */
1985     item2.mask = LVIF_TEXT;
1986     item2.iItem = 2;
1987     item2.iSubItem = 0;
1988     item2.pszText = item2text;
1989     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1990     expect(2, r);
1991
1992     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1993     expect(3, r);
1994
1995     /* [item0, item1] */
1996     r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0);
1997     expect(TRUE, r);
1998
1999     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2000     expect(2, r);
2001
2002     /* [] */
2003     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
2004     expect(TRUE, r);
2005
2006     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2007     expect(0, r);
2008
2009     /* [item0] */
2010     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
2011     expect(0, r);
2012
2013     /* [item0, item1] */
2014     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
2015     expect(1, r);
2016
2017     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2018     expect(2, r);
2019
2020     /* [item0, item1, item2] */
2021     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
2022     expect(2, r);
2023
2024     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2025     expect(3, r);
2026
2027     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2028
2029     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2030     DestroyWindow(hwnd);
2031 }
2032
2033 static void test_item_position(void)
2034 {
2035     /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2036
2037     HWND hwnd;
2038     DWORD r;
2039     POINT position;
2040
2041     LVITEM item0;
2042     LVITEM item1;
2043     LVITEM item2;
2044     static CHAR item0text[] = "item0";
2045     static CHAR item1text[] = "item1";
2046     static CHAR item2text[] = "item2";
2047
2048     hwnd = create_listview_control(LVS_ICON);
2049     ok(hwnd != NULL, "failed to create a listview window\n");
2050
2051     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2052
2053     /* [item0] */
2054     item0.mask = LVIF_TEXT;
2055     item0.iItem = 0;
2056     item0.iSubItem = 0;
2057     item0.pszText = item0text;
2058     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
2059     expect(0, r);
2060
2061     /* [item0, item1] */
2062     item1.mask = LVIF_TEXT;
2063     item1.iItem = 1;
2064     item1.iSubItem = 0;
2065     item1.pszText = item1text;
2066     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
2067     expect(1, r);
2068
2069     /* [item0, item1, item2] */
2070     item2.mask = LVIF_TEXT;
2071     item2.iItem = 2;
2072     item2.iSubItem = 0;
2073     item2.pszText = item2text;
2074     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
2075     expect(2, r);
2076
2077     r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2078     expect(TRUE, r);
2079     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2080     expect(TRUE, r);
2081     expect2(10, 5, position.x, position.y);
2082
2083     r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2084     expect(TRUE, r);
2085     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2086     expect(TRUE, r);
2087     expect2(0, 0, position.x, position.y);
2088
2089     r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2090     expect(TRUE, r);
2091     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2092     expect(TRUE, r);
2093     expect2(20, 20, position.x, position.y);
2094
2095     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2096
2097     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2098     DestroyWindow(hwnd);
2099 }
2100
2101 static void test_getorigin(void)
2102 {
2103     /* LVM_GETORIGIN */
2104
2105     HWND hwnd;
2106     DWORD r;
2107     POINT position;
2108
2109     position.x = position.y = 0;
2110
2111     hwnd = create_listview_control(LVS_ICON);
2112     ok(hwnd != NULL, "failed to create a listview window\n");
2113     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2114
2115     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2116     expect(TRUE, r);
2117     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2118     DestroyWindow(hwnd);
2119
2120     hwnd = create_listview_control(LVS_SMALLICON);
2121     ok(hwnd != NULL, "failed to create a listview window\n");
2122     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2123
2124     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2125     expect(TRUE, r);
2126     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2127     DestroyWindow(hwnd);
2128
2129     hwnd = create_listview_control(LVS_LIST);
2130     ok(hwnd != NULL, "failed to create a listview window\n");
2131     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2132
2133     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2134     expect(FALSE, r);
2135     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2136     DestroyWindow(hwnd);
2137
2138     hwnd = create_listview_control(LVS_REPORT);
2139     ok(hwnd != NULL, "failed to create a listview window\n");
2140     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2141
2142     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2143     expect(FALSE, r);
2144     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2145     DestroyWindow(hwnd);
2146 }
2147
2148 static void test_multiselect(void)
2149 {
2150     typedef struct t_select_task
2151     {
2152         const char *descr;
2153         int initPos;
2154         int loopVK;
2155         int count;
2156         int result;
2157     } select_task;
2158
2159     HWND hwnd;
2160     INT r;
2161     int i,j,item_count,selected_count;
2162     static const int items=5;
2163     BYTE kstate[256];
2164     select_task task;
2165     LONG_PTR style;
2166     LVITEMA item;
2167
2168     static struct t_select_task task_list[] = {
2169         { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2170         { "using VK_UP", -1, VK_UP, -1, -1 },
2171         { "using VK_END", 0, VK_END, 1, -1 },
2172         { "using VK_HOME", -1, VK_HOME, 1, -1 }
2173     };
2174
2175     hwnd = create_listview_control(LVS_REPORT);
2176
2177     for (i = 0; i < items; i++)
2178         insert_item(hwnd, 0);
2179
2180     item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2181     expect(items, item_count);
2182
2183     for (i = 0; i < 4; i++) {
2184         LVITEMA item;
2185
2186         task = task_list[i];
2187
2188         /* deselect all items */
2189         item.state = 0;
2190         item.stateMask = LVIS_SELECTED;
2191         SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2192         SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2193
2194         /* set initial position */
2195         SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2196
2197         item.state = LVIS_SELECTED;
2198         item.stateMask = LVIS_SELECTED;
2199         SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2200
2201         selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2202         ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2203
2204         /* Set SHIFT key pressed */
2205         GetKeyboardState(kstate);
2206         kstate[VK_SHIFT]=0x80;
2207         SetKeyboardState(kstate);
2208
2209         for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2210             r = SendMessage(hwnd, WM_KEYDOWN, task.loopVK, 0);
2211             expect(0,r);
2212             r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
2213             expect(0,r);
2214         }
2215
2216         selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2217
2218         ok((task.result == -1 ? item_count : task.result) == selected_count, "Failed multiple selection %s. There should be %d selected items (is %d)\n", task.descr, item_count, selected_count);
2219
2220         /* Set SHIFT key released */
2221         GetKeyboardState(kstate);
2222         kstate[VK_SHIFT]=0x00;
2223         SetKeyboardState(kstate);
2224     }
2225     DestroyWindow(hwnd);
2226
2227     /* make multiple selection, then switch to LVS_SINGLESEL */
2228     hwnd = create_listview_control(LVS_REPORT);
2229     for (i=0;i<items;i++) {
2230             insert_item(hwnd, 0);
2231     }
2232     item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
2233     expect(items,item_count);
2234
2235     /* try with NULL pointer */
2236     r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2237     expect(FALSE, r);
2238
2239     /* select all, check notifications */
2240     item.state = 0;
2241     item.stateMask = LVIS_SELECTED;
2242     SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2243
2244     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2245
2246     item.stateMask = LVIS_SELECTED;
2247     item.state     = LVIS_SELECTED;
2248     r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2249     expect(TRUE, r);
2250
2251     ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2252                 "select all notification", FALSE);
2253
2254     /* select all again (all selected already) */
2255     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2256
2257     memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2258
2259     item.stateMask = LVIS_SELECTED;
2260     item.state     = LVIS_SELECTED;
2261     r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2262     expect(TRUE, r);
2263
2264     ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2265     ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2266     ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2267
2268     ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2269                 "select all notification 2", FALSE);
2270
2271     /* deselect all items */
2272     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2273
2274     item.state = 0;
2275     item.stateMask = LVIS_SELECTED;
2276     SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2277
2278     ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2279                 "deselect all notification", FALSE);
2280
2281     /* deselect all items again */
2282     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2283     item.state = 0;
2284     item.stateMask = LVIS_SELECTED;
2285     SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2286     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2287
2288     /* any non-zero state value does the same */
2289     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2290
2291     memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2292
2293     item.stateMask = LVIS_SELECTED;
2294     item.state     = LVIS_CUT;
2295     r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2296     expect(TRUE, r);
2297
2298     ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2299     ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2300     ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2301
2302     ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2303                 "set state all notification 3", FALSE);
2304
2305     SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2306     for (i = 0; i < 3; i++) {
2307         item.state = LVIS_SELECTED;
2308         item.stateMask = LVIS_SELECTED;
2309         SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2310     }
2311
2312     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2313     expect(3, r);
2314     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2315     expect(-1, r);
2316
2317     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2318     ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2319     SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2320     /* check that style is accepted */
2321     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2322     ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2323
2324     for (i=0;i<3;i++) {
2325         r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
2326         ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2327     }
2328     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2329     expect(3, r);
2330     SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2331     expect(3, r);
2332
2333     /* select one more */
2334     item.state = LVIS_SELECTED;
2335     item.stateMask = LVIS_SELECTED;
2336     SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2337
2338     for (i=0;i<3;i++) {
2339         r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
2340         ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2341     }
2342     r = ListView_GetItemState(hwnd, 3, LVIS_SELECTED);
2343     ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2344
2345     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2346     expect(1, r);
2347     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2348     expect(-1, r);
2349
2350     /* try to select all on LVS_SINGLESEL */
2351     memset(&item, 0, sizeof(item));
2352     item.stateMask = LVIS_SELECTED;
2353     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2354     expect(TRUE, r);
2355     SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2356
2357     item.stateMask = LVIS_SELECTED;
2358     item.state     = LVIS_SELECTED;
2359     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2360     expect(FALSE, r);
2361
2362     r = ListView_GetSelectedCount(hwnd);
2363     expect(0, r);
2364     r = ListView_GetSelectionMark(hwnd);
2365     expect(-1, r);
2366
2367     /* try to deselect all on LVS_SINGLESEL */
2368     item.stateMask = LVIS_SELECTED;
2369     item.state     = LVIS_SELECTED;
2370     r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2371     expect(TRUE, r);
2372
2373     item.stateMask = LVIS_SELECTED;
2374     item.state     = 0;
2375     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2376     expect(TRUE, r);
2377     r = ListView_GetSelectedCount(hwnd);
2378     expect(0, r);
2379
2380     /* 1. selection mark is update when new focused item is set */
2381     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2382     SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2383
2384     r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2385     expect(-1, r);
2386
2387     item.stateMask = LVIS_FOCUSED;
2388     item.state     = LVIS_FOCUSED;
2389     r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2390     expect(TRUE, r);
2391
2392     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2393     expect(0, r);
2394
2395     /* it's not updated if already set */
2396     item.stateMask = LVIS_FOCUSED;
2397     item.state     = LVIS_FOCUSED;
2398     r = SendMessage(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2399     expect(TRUE, r);
2400
2401     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2402     expect(0, r);
2403
2404     r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2405     expect(0, r);
2406
2407     item.stateMask = LVIS_FOCUSED;
2408     item.state     = LVIS_FOCUSED;
2409     r = SendMessage(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2410     expect(TRUE, r);
2411
2412     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2413     expect(-1, r);
2414
2415     /* need to reset focused item first */
2416     item.stateMask = LVIS_FOCUSED;
2417     item.state     = 0;
2418     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2419     expect(TRUE, r);
2420
2421     item.stateMask = LVIS_FOCUSED;
2422     item.state     = LVIS_FOCUSED;
2423     r = SendMessage(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2424     expect(TRUE, r);
2425
2426     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2427     expect(2, r);
2428
2429     item.stateMask = LVIS_FOCUSED;
2430     item.state     = 0;
2431     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2432     expect(TRUE, r);
2433
2434     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2435     expect(2, r);
2436
2437     /* 2. same tests, with LVM_SETITEM */
2438     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2439     SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2440
2441     r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2442     expect(2, r);
2443
2444     item.stateMask = LVIS_FOCUSED;
2445     item.state     = LVIS_FOCUSED;
2446     item.mask      = LVIF_STATE;
2447     item.iItem = item.iSubItem = 0;
2448     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2449     expect(TRUE, r);
2450
2451     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2452     expect(0, r);
2453
2454     /* it's not updated if already set */
2455     item.stateMask = LVIS_FOCUSED;
2456     item.state     = LVIS_FOCUSED;
2457     item.mask      = LVIF_STATE;
2458     item.iItem     = 1;
2459     item.iSubItem  = 0;
2460     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2461     expect(TRUE, r);
2462
2463     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2464     expect(0, r);
2465
2466     r = SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2467     expect(0, r);
2468
2469     item.stateMask = LVIS_FOCUSED;
2470     item.state     = LVIS_FOCUSED;
2471     item.mask      = LVIF_STATE;
2472     item.iItem     = 1;
2473     item.iSubItem  = 0;
2474     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2475     expect(TRUE, r);
2476
2477     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2478     expect(-1, r);
2479
2480     /* need to reset focused item first */
2481     item.stateMask = LVIS_FOCUSED;
2482     item.state     = 0;
2483     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2484     expect(TRUE, r);
2485
2486     item.stateMask = LVIS_FOCUSED;
2487     item.state     = LVIS_FOCUSED;
2488     item.mask      = LVIF_STATE;
2489     item.iItem     = 2;
2490     item.iSubItem  = 0;
2491     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2492     expect(TRUE, r);
2493
2494     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2495     expect(2, r);
2496
2497     item.stateMask = LVIS_FOCUSED;
2498     item.state     = 0;
2499     r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2500     expect(TRUE, r);
2501
2502     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2503     expect(2, r);
2504
2505     DestroyWindow(hwnd);
2506 }
2507
2508 static void test_subitem_rect(void)
2509 {
2510     HWND hwnd;
2511     DWORD r;
2512     LVCOLUMN col;
2513     RECT rect, rect2;
2514     INT arr[3];
2515
2516     /* test LVM_GETSUBITEMRECT for header */
2517     hwnd = create_listview_control(LVS_REPORT);
2518     ok(hwnd != NULL, "failed to create a listview window\n");
2519     /* add some columns */
2520     memset(&col, 0, sizeof(LVCOLUMN));
2521     col.mask = LVCF_WIDTH;
2522     col.cx = 100;
2523     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
2524     expect(0, r);
2525     col.cx = 150;
2526     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
2527     expect(1, r);
2528     col.cx = 200;
2529     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
2530     expect(2, r);
2531     /* item = -1 means header, subitem index is 1 based */
2532     rect.left = LVIR_BOUNDS;
2533     rect.top  = 0;
2534     rect.right = rect.bottom = 0;
2535     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2536     expect(0, r);
2537
2538     rect.left = LVIR_BOUNDS;
2539     rect.top  = 1;
2540     rect.right = rect.bottom = 0;
2541     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2542     expect(1, r);
2543
2544     expect(100, rect.left);
2545     expect(250, rect.right);
2546     expect(3, rect.top);
2547
2548     rect.left = LVIR_BOUNDS;
2549     rect.top  = 2;
2550     rect.right = rect.bottom = 0;
2551     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2552     expect(1, r);
2553
2554     expect(250, rect.left);
2555     expect(450, rect.right);
2556     expect(3, rect.top);
2557
2558     /* item LVS_REPORT padding isn't applied to subitems */
2559     insert_item(hwnd, 0);
2560
2561     rect.left = LVIR_BOUNDS;
2562     rect.top  = 1;
2563     rect.right = rect.bottom = 0;
2564     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2565     expect(1, r);
2566     expect(100, rect.left);
2567     expect(250, rect.right);
2568
2569     rect.left = LVIR_ICON;
2570     rect.top  = 1;
2571     rect.right = rect.bottom = 0;
2572     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2573     expect(1, r);
2574     /* no icon attached - zero width rectangle, with no left padding */
2575     expect(100, rect.left);
2576     expect(100, rect.right);
2577
2578     rect.left = LVIR_LABEL;
2579     rect.top  = 1;
2580     rect.right = rect.bottom = 0;
2581     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2582     expect(1, r);
2583     /* same as full LVIR_BOUNDS */
2584     expect(100, rect.left);
2585     expect(250, rect.right);
2586
2587     SendMessage(hwnd, LVM_SCROLL, 10, 0);
2588
2589     rect.left = LVIR_BOUNDS;
2590     rect.top  = 1;
2591     rect.right = rect.bottom = 0;
2592     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2593     expect(1, r);
2594     expect(90, rect.left);
2595     expect(240, rect.right);
2596
2597     SendMessage(hwnd, LVM_SCROLL, -10, 0);
2598
2599     /* test header interaction */
2600     subclass_header(hwnd);
2601     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2602
2603     rect.left = LVIR_BOUNDS;
2604     rect.top  = 1;
2605     rect.right = rect.bottom = 0;
2606     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2607     expect(1, r);
2608
2609     rect.left = LVIR_BOUNDS;
2610     rect.top  = 1;
2611     rect.right = rect.bottom = 0;
2612     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2613     expect(1, r);
2614
2615     rect.left = LVIR_BOUNDS;
2616     rect.top  = 1;
2617     rect.right = rect.bottom = 0;
2618     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2619     expect(1, r);
2620
2621     rect.left = LVIR_BOUNDS;
2622     rect.top  = 1;
2623     rect.right = rect.bottom = 0;
2624     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2625     expect(1, r);
2626
2627     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2628
2629     DestroyWindow(hwnd);
2630
2631     /* test subitem rects after re-arranging columns */
2632     hwnd = create_listview_control(LVS_REPORT);
2633     ok(hwnd != NULL, "failed to create a listview window\n");
2634     memset(&col, 0, sizeof(LVCOLUMN));
2635     col.mask = LVCF_WIDTH;
2636
2637     col.cx = 100;
2638     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
2639     expect(0, r);
2640
2641     col.cx = 200;
2642     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
2643     expect(1, r);
2644
2645     col.cx = 300;
2646     r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
2647     expect(2, r);
2648
2649     insert_item(hwnd, 0);
2650     insert_item(hwnd, 1);
2651
2652     /* wrong item is refused for main item */
2653     rect.left = LVIR_BOUNDS;
2654     rect.top  = 0;
2655     rect.right = rect.bottom = -1;
2656     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2657     expect(FALSE, r);
2658
2659     /* for subitems rectangle is calculated even if there's no item added */
2660     rect.left = LVIR_BOUNDS;
2661     rect.top  = 1;
2662     rect.right = rect.bottom = -1;
2663     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2664     expect(TRUE, r);
2665
2666     rect2.left = LVIR_BOUNDS;
2667     rect2.top  = 1;
2668     rect2.right = rect2.bottom = -1;
2669     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2670     expect(TRUE, r);
2671     expect(rect.right, rect2.right);
2672     expect(rect.left, rect2.left);
2673     expect(rect.bottom, rect2.top);
2674     ok(rect2.bottom > rect2.top, "expected not zero height\n");
2675
2676     arr[0] = 1; arr[1] = 0; arr[2] = 2;
2677     r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2678     expect(TRUE, r);
2679
2680     rect.left = LVIR_BOUNDS;
2681     rect.top  = 0;
2682     rect.right = rect.bottom = -1;
2683     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2684     expect(TRUE, r);
2685     expect(0, rect.left);
2686     expect(600, rect.right);
2687
2688     rect.left = LVIR_BOUNDS;
2689     rect.top  = 1;
2690     rect.right = rect.bottom = -1;
2691     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2692     expect(TRUE, r);
2693     expect(0, rect.left);
2694     expect(200, rect.right);
2695
2696     rect2.left = LVIR_BOUNDS;
2697     rect2.top  = 1;
2698     rect2.right = rect2.bottom = -1;
2699     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2700     expect(TRUE, r);
2701     expect(0, rect2.left);
2702     expect(200, rect2.right);
2703     /* items are of the same height */
2704     ok(rect2.top > 0, "expected positive item height\n");
2705     expect(rect.bottom, rect2.top);
2706     expect(rect.bottom * 2 - rect.top, rect2.bottom);
2707
2708     rect.left = LVIR_BOUNDS;
2709     rect.top  = 2;
2710     rect.right = rect.bottom = -1;
2711     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2712     expect(TRUE, r);
2713     expect(300, rect.left);
2714     expect(600, rect.right);
2715
2716     DestroyWindow(hwnd);
2717
2718     /* try it for non LVS_REPORT style */
2719     hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2720                          GetModuleHandle(NULL), 0);
2721     rect.left = LVIR_BOUNDS;
2722     rect.top  = 1;
2723     rect.right = rect.bottom = -10;
2724     r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2725     expect(0, r);
2726     /* rect is unchanged */
2727     expect(0, rect.left);
2728     expect(-10, rect.right);
2729     expect(1, rect.top);
2730     expect(-10, rect.bottom);
2731     DestroyWindow(hwnd);
2732 }
2733
2734 /* comparison callback for test_sorting */
2735 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2736 {
2737     if (first == second) return 0;
2738     return (first > second ? 1 : -1);
2739 }
2740
2741 static void test_sorting(void)
2742 {
2743     HWND hwnd;
2744     LVITEMA item = {0};
2745     INT r;
2746     LONG_PTR style;
2747     static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2748     CHAR buff[10];
2749
2750     hwnd = create_listview_control(LVS_REPORT);
2751     ok(hwnd != NULL, "failed to create a listview window\n");
2752
2753     /* insert some items */
2754     item.mask = LVIF_PARAM | LVIF_STATE;
2755     item.state = LVIS_SELECTED;
2756     item.iItem = 0;
2757     item.iSubItem = 0;
2758     item.lParam = 3;
2759     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2760     expect(0, r);
2761
2762     item.mask = LVIF_PARAM;
2763     item.iItem = 1;
2764     item.iSubItem = 0;
2765     item.lParam = 2;
2766     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2767     expect(1, r);
2768
2769     item.mask = LVIF_STATE | LVIF_PARAM;
2770     item.state = LVIS_SELECTED;
2771     item.iItem = 2;
2772     item.iSubItem = 0;
2773     item.lParam = 4;
2774     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2775     expect(2, r);
2776
2777     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2778     expect(-1, r);
2779
2780     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2781     expect(2, r);
2782
2783     r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2784     expect(TRUE, r);
2785
2786     r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2787     expect(2, r);
2788     r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2789     expect(-1, r);
2790     r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2791     expect(0, r);
2792     r = SendMessage(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2793     expect(LVIS_SELECTED, r);
2794     r = SendMessage(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2795     expect(LVIS_SELECTED, r);
2796
2797     DestroyWindow(hwnd);
2798
2799     /* switch to LVS_SORTASCENDING when some items added */
2800     hwnd = create_listview_control(LVS_REPORT);
2801     ok(hwnd != NULL, "failed to create a listview window\n");
2802
2803     item.mask = LVIF_TEXT;
2804     item.iItem = 0;
2805     item.iSubItem = 0;
2806     item.pszText = names[1];
2807     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2808     expect(0, r);
2809
2810     item.mask = LVIF_TEXT;
2811     item.iItem = 1;
2812     item.iSubItem = 0;
2813     item.pszText = names[2];
2814     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2815     expect(1, r);
2816
2817     item.mask = LVIF_TEXT;
2818     item.iItem = 2;
2819     item.iSubItem = 0;
2820     item.pszText = names[0];
2821     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2822     expect(2, r);
2823
2824     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2825     SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2826     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2827     ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2828
2829     /* no sorting performed when switched to LVS_SORTASCENDING */
2830     item.mask = LVIF_TEXT;
2831     item.iItem = 0;
2832     item.pszText = buff;
2833     item.cchTextMax = sizeof(buff);
2834     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2835     expect(TRUE, r);
2836     ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2837
2838     item.iItem = 1;
2839     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2840     expect(TRUE, r);
2841     ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2842
2843     item.iItem = 2;
2844     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2845     expect(TRUE, r);
2846     ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2847
2848     /* adding new item doesn't resort list */
2849     item.mask = LVIF_TEXT;
2850     item.iItem = 3;
2851     item.iSubItem = 0;
2852     item.pszText = names[3];
2853     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2854     expect(3, r);
2855
2856     item.mask = LVIF_TEXT;
2857     item.iItem = 0;
2858     item.pszText = buff;
2859     item.cchTextMax = sizeof(buff);
2860     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2861     expect(TRUE, r);
2862     ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2863
2864     item.iItem = 1;
2865     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2866     expect(TRUE, r);
2867     ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2868
2869     item.iItem = 2;
2870     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2871     expect(TRUE, r);
2872     ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2873
2874     item.iItem = 3;
2875     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2876     expect(TRUE, r);
2877     ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2878
2879     /* corner case - item should be placed at first position */
2880     item.mask = LVIF_TEXT;
2881     item.iItem = 4;
2882     item.iSubItem = 0;
2883     item.pszText = names[4];
2884     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2885     expect(0, r);
2886
2887     item.iItem = 0;
2888     item.pszText = buff;
2889     item.cchTextMax = sizeof(buff);
2890     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2891     expect(TRUE, r);
2892     ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2893
2894     item.iItem = 1;
2895     item.pszText = buff;
2896     item.cchTextMax = sizeof(buff);
2897     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2898     expect(TRUE, r);
2899     ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2900
2901     item.iItem = 2;
2902     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2903     expect(TRUE, r);
2904     ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2905
2906     item.iItem = 3;
2907     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2908     expect(TRUE, r);
2909     ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2910
2911     item.iItem = 4;
2912     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2913     expect(TRUE, r);
2914     ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2915
2916     DestroyWindow(hwnd);
2917 }
2918
2919 static void test_ownerdata(void)
2920 {
2921     static char test_str[] = "test";
2922
2923     HWND hwnd;
2924     LONG_PTR style, ret;
2925     DWORD res;
2926     LVITEMA item;
2927
2928     /* it isn't possible to set LVS_OWNERDATA after creation */
2929     if (g_is_below_5)
2930     {
2931         win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2932     }
2933     else
2934     {
2935         hwnd = create_listview_control(LVS_REPORT);
2936         ok(hwnd != NULL, "failed to create a listview window\n");
2937         style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2938         ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
2939
2940         flush_sequences(sequences, NUM_MSG_SEQUENCES);
2941
2942         ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2943         ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2944         ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2945                 "try to switch to LVS_OWNERDATA seq", FALSE);
2946
2947         style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2948         ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
2949         DestroyWindow(hwnd);
2950     }
2951
2952     /* try to set LVS_OWNERDATA after creation just having it */
2953     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2954     ok(hwnd != NULL, "failed to create a listview window\n");
2955     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2956     ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2957
2958     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2959
2960     ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2961     ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2962     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2963                 "try to switch to LVS_OWNERDATA seq", FALSE);
2964     DestroyWindow(hwnd);
2965
2966     /* try to remove LVS_OWNERDATA after creation just having it */
2967     if (g_is_below_5)
2968     {
2969         win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2970     }
2971     else
2972     {
2973         hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2974         ok(hwnd != NULL, "failed to create a listview window\n");
2975         style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2976         ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2977
2978         flush_sequences(sequences, NUM_MSG_SEQUENCES);
2979
2980         ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
2981         ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2982         ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2983                 "try to switch to LVS_OWNERDATA seq", FALSE);
2984         style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2985         ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2986         DestroyWindow(hwnd);
2987     }
2988
2989     /* try select an item */
2990     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2991     ok(hwnd != NULL, "failed to create a listview window\n");
2992     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2993     expect(1, res);
2994     res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2995     expect(0, res);
2996     memset(&item, 0, sizeof(item));
2997     item.stateMask = LVIS_SELECTED;
2998     item.state     = LVIS_SELECTED;
2999     res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3000     expect(TRUE, res);
3001     res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3002     expect(1, res);
3003     res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3004     expect(1, res);
3005     DestroyWindow(hwnd);
3006
3007     /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3008     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3009     ok(hwnd != NULL, "failed to create a listview window\n");
3010     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3011     expect(1, res);
3012     res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3013     expect(1, res);
3014     memset(&item, 0, sizeof(item));
3015     item.mask = LVIF_STATE;
3016     item.iItem = 0;
3017     item.stateMask = LVIS_SELECTED;
3018     item.state     = LVIS_SELECTED;
3019     res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3020     expect(FALSE, res);
3021     memset(&item, 0, sizeof(item));
3022     item.pszText = test_str;
3023     res = SendMessageA(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
3024     expect(FALSE, res);
3025     DestroyWindow(hwnd);
3026
3027     /* check notifications after focused/selected changed */
3028     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3029     ok(hwnd != NULL, "failed to create a listview window\n");
3030     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3031     expect(1, res);
3032
3033     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3034
3035     memset(&item, 0, sizeof(item));
3036     item.stateMask = LVIS_SELECTED;
3037     item.state     = LVIS_SELECTED;
3038     res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3039     expect(TRUE, res);
3040
3041     ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
3042                 "ownerdata select notification", TRUE);
3043
3044     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3045
3046     memset(&item, 0, sizeof(item));
3047     item.stateMask = LVIS_FOCUSED;
3048     item.state     = LVIS_FOCUSED;
3049     res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3050     expect(TRUE, res);
3051
3052     ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
3053                 "ownerdata focus notification", TRUE);
3054
3055     /* select all, check notifications */
3056     item.stateMask = LVIS_SELECTED;
3057     item.state     = 0;
3058     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3059     expect(TRUE, res);
3060
3061     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3062
3063     item.stateMask = LVIS_SELECTED;
3064     item.state     = LVIS_SELECTED;
3065
3066     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3067     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3068     expect(TRUE, res);
3069     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3070     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3071     ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3072     ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3073     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3074     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3075     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3076
3077     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3078                 "ownerdata select all notification", FALSE);
3079
3080     /* select all again, note that all items are selected already */
3081     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3082     item.stateMask = LVIS_SELECTED;
3083     item.state     = LVIS_SELECTED;
3084
3085     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3086     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3087     expect(TRUE, res);
3088     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3089     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3090     ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3091     ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3092     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3093     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3094     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3095
3096     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3097                 "ownerdata select all notification", FALSE);
3098
3099     /* deselect all */
3100     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3101     item.stateMask = LVIS_SELECTED;
3102     item.state     = 0;
3103
3104     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3105     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3106     expect(TRUE, res);
3107     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3108     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3109     ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3110     ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3111     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3112     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3113     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3114
3115     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3116                 "ownerdata deselect all notification", TRUE);
3117
3118     /* nothing selected, deselect all again */
3119     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3120     item.stateMask = LVIS_SELECTED;
3121     item.state     = 0;
3122
3123     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3124     expect(TRUE, res);
3125
3126     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3127
3128     /* select one, then deselect all */
3129     item.stateMask = LVIS_SELECTED;
3130     item.state     = LVIS_SELECTED;
3131     res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3132     expect(TRUE, res);
3133     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3134     item.stateMask = LVIS_SELECTED;
3135     item.state     = 0;
3136
3137     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3138     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3139     expect(TRUE, res);
3140     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3141     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3142     ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3143     ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3144     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3145     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3146     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3147
3148     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3149                 "ownerdata select all notification", TRUE);
3150
3151     /* remove focused, try to focus all */
3152     item.stateMask = LVIS_FOCUSED;
3153     item.state     = LVIS_FOCUSED;
3154     res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3155     expect(TRUE, res);
3156     item.stateMask = LVIS_FOCUSED;
3157     item.state     = 0;
3158     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3159     expect(TRUE, res);
3160     item.stateMask = LVIS_FOCUSED;
3161     res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3162     expect(0, res);
3163
3164     /* setting all to focused returns failure value */
3165     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3166     item.stateMask = LVIS_FOCUSED;
3167     item.state     = LVIS_FOCUSED;
3168
3169     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3170     expect(FALSE, res);
3171
3172     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3173                 "ownerdata focus all notification", FALSE);
3174
3175     /* focus single item, remove all */
3176     item.stateMask = LVIS_FOCUSED;
3177     item.state     = LVIS_FOCUSED;
3178     res = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3179     expect(TRUE, res);
3180     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3181     item.stateMask = LVIS_FOCUSED;
3182     item.state     = 0;
3183
3184     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3185     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3186     expect(TRUE, res);
3187     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3188     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3189     ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3190     ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3191     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3192     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3193     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3194
3195     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3196                 "ownerdata remove focus all notification", TRUE);
3197
3198     /* set all cut */
3199     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3200     item.stateMask = LVIS_CUT;
3201     item.state     = LVIS_CUT;
3202
3203     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3204     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3205     expect(TRUE, res);
3206     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3207     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3208     ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3209     ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3210     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3211     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3212     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3213
3214     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3215                 "ownerdata cut all notification", FALSE);
3216
3217     /* all marked cut, try again */
3218     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3219     item.stateMask = LVIS_CUT;
3220     item.state     = LVIS_CUT;
3221
3222     memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3223     res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3224     expect(TRUE, res);
3225     ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3226     ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3227     ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3228     ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3229     ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3230     ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3231     ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3232
3233     ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3234                 "ownerdata cut all notification #2", FALSE);
3235
3236     DestroyWindow(hwnd);
3237
3238     /* check notifications on LVM_GETITEM */
3239     /* zero callback mask */
3240     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3241     ok(hwnd != NULL, "failed to create a listview window\n");
3242     res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3243     expect(1, res);
3244
3245     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3246
3247     memset(&item, 0, sizeof(item));
3248     item.stateMask = LVIS_SELECTED;
3249     item.mask      = LVIF_STATE;
3250     res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3251     expect(TRUE, res);
3252
3253     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3254                 "ownerdata getitem selected state 1", FALSE);
3255
3256     /* non zero callback mask but not we asking for */
3257     res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3258     expect(TRUE, res);
3259
3260     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3261
3262     memset(&item, 0, sizeof(item));
3263     item.stateMask = LVIS_SELECTED;
3264     item.mask      = LVIF_STATE;
3265     res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3266     expect(TRUE, res);
3267
3268     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3269                 "ownerdata getitem selected state 2", FALSE);
3270
3271     /* LVIS_OVERLAYMASK callback mask, asking for index */
3272     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3273
3274     memset(&item, 0, sizeof(item));
3275     item.stateMask = LVIS_OVERLAYMASK;
3276     item.mask      = LVIF_STATE;
3277     res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3278     expect(TRUE, res);
3279
3280     ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3281                 "ownerdata getitem selected state 2", FALSE);
3282
3283     DestroyWindow(hwnd);
3284
3285     /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3286     hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3287     ok(hwnd != NULL, "failed to create a listview window\n");
3288     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3289     ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3290     ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3291     SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3292     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3293     ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3294     DestroyWindow(hwnd);
3295     /* apparently it's allowed to switch these style on after creation */
3296     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3297     ok(hwnd != NULL, "failed to create a listview window\n");
3298     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3299     ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3300     SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3301     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3302     ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3303     DestroyWindow(hwnd);
3304
3305     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3306     ok(hwnd != NULL, "failed to create a listview window\n");
3307     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3308     ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3309     SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3310     style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3311     ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3312     DestroyWindow(hwnd);
3313 }
3314
3315 static void test_norecompute(void)
3316 {
3317     static CHAR testA[] = "test";
3318     CHAR buff[10];
3319     LVITEMA item;
3320     HWND hwnd;
3321     DWORD res;
3322
3323     /* self containing control */
3324     hwnd = create_listview_control(LVS_REPORT);
3325     ok(hwnd != NULL, "failed to create a listview window\n");
3326     memset(&item, 0, sizeof(item));
3327     item.mask = LVIF_TEXT | LVIF_STATE;
3328     item.iItem = 0;
3329     item.stateMask = LVIS_SELECTED;
3330     item.state     = LVIS_SELECTED;
3331     item.pszText   = testA;
3332     res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
3333     expect(0, res);
3334     /* retrieve with LVIF_NORECOMPUTE */
3335     item.mask  = LVIF_TEXT | LVIF_NORECOMPUTE;
3336     item.iItem = 0;
3337     item.pszText    = buff;
3338     item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3339     res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
3340     expect(TRUE, res);
3341     ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3342
3343     item.mask = LVIF_TEXT;
3344     item.iItem = 1;
3345     item.pszText = LPSTR_TEXTCALLBACK;
3346     res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
3347     expect(1, res);
3348
3349     item.mask  = LVIF_TEXT | LVIF_NORECOMPUTE;
3350     item.iItem = 1;
3351     item.pszText    = buff;
3352     item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3353
3354     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3355     res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
3356     expect(TRUE, res);
3357     ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
3358        LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
3359     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3360
3361     DestroyWindow(hwnd);
3362
3363     /* LVS_OWNERDATA */
3364     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3365     ok(hwnd != NULL, "failed to create a listview window\n");
3366
3367     item.mask = LVIF_STATE;
3368     item.stateMask = LVIS_SELECTED;
3369     item.state     = LVIS_SELECTED;
3370     item.iItem = 0;
3371     res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
3372     expect(0, res);
3373
3374     item.mask  = LVIF_TEXT | LVIF_NORECOMPUTE;
3375     item.iItem = 0;
3376     item.pszText    = buff;
3377     item.cchTextMax = sizeof(buff)/sizeof(CHAR);
3378     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3379     res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
3380     expect(TRUE, res);
3381     ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
3382        LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
3383     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3384
3385     DestroyWindow(hwnd);
3386 }
3387
3388 static void test_nosortheader(void)
3389 {
3390     HWND hwnd, header;
3391     LONG_PTR style;
3392
3393     hwnd = create_listview_control(LVS_REPORT);
3394     ok(hwnd != NULL, "failed to create a listview window\n");
3395
3396     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3397     ok(IsWindow(header), "header expected\n");
3398
3399     style = GetWindowLongPtr(header, GWL_STYLE);
3400     ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3401
3402     style = GetWindowLongPtr(hwnd, GWL_STYLE);
3403     SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3404     /* HDS_BUTTONS retained */
3405     style = GetWindowLongPtr(header, GWL_STYLE);
3406     ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3407
3408     DestroyWindow(hwnd);
3409
3410     /* create with LVS_NOSORTHEADER */
3411     hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3412     ok(hwnd != NULL, "failed to create a listview window\n");
3413
3414     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3415     ok(IsWindow(header), "header expected\n");
3416
3417     style = GetWindowLongPtr(header, GWL_STYLE);
3418     ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3419
3420     style = GetWindowLongPtr(hwnd, GWL_STYLE);
3421     SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3422     /* not changed here */
3423     style = GetWindowLongPtr(header, GWL_STYLE);
3424     ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3425
3426     DestroyWindow(hwnd);
3427 }
3428
3429 static void test_setredraw(void)
3430 {
3431     HWND hwnd;
3432     DWORD_PTR style;
3433     DWORD ret;
3434     HDC hdc;
3435     RECT rect;
3436
3437     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3438     ok(hwnd != NULL, "failed to create a listview window\n");
3439
3440     /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3441        ListView seems to handle it internally without DefWinProc */
3442
3443     /* default value first */
3444     ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
3445     expect(0, ret);
3446     /* disable */
3447     style = GetWindowLongPtr(hwnd, GWL_STYLE);
3448     ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3449     ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3450     expect(0, ret);
3451     style = GetWindowLongPtr(hwnd, GWL_STYLE);
3452     ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3453     ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
3454     expect(0, ret);
3455
3456     /* check update rect after redrawing */
3457     ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3458     expect(0, ret);
3459     InvalidateRect(hwnd, NULL, FALSE);
3460     RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3461     rect.right = rect.bottom = 1;
3462     GetUpdateRect(hwnd, &rect, FALSE);
3463     expect(0, rect.right);
3464     expect(0, rect.bottom);
3465
3466     /* WM_ERASEBKGND */
3467     hdc = GetWindowDC(hwndparent);
3468     ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3469     expect(TRUE, ret);
3470     ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3471     expect(0, ret);
3472     ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3473     expect(TRUE, ret);
3474     ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
3475     expect(0, ret);
3476     ReleaseDC(hwndparent, hdc);
3477
3478     /* check notification messages to show that repainting is disabled */
3479     ret = SendMessage(hwnd, LVM_SETITEMCOUNT, 1, 0);
3480     expect(TRUE, ret);
3481     ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3482     expect(0, ret);
3483     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3484
3485     InvalidateRect(hwnd, NULL, TRUE);
3486     UpdateWindow(hwnd);
3487     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3488                 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3489
3490     ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3491     expect(TRUE, ret);
3492     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3493     InvalidateRect(hwnd, NULL, TRUE);
3494     UpdateWindow(hwnd);
3495     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3496                 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3497
3498     /* message isn't forwarded to header */
3499     subclass_header(hwnd);
3500     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3501     ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
3502     expect(0, ret);
3503     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3504                 "WM_SETREDRAW: not forwarded to header", FALSE);
3505
3506     DestroyWindow(hwnd);
3507 }
3508
3509 static void test_hittest(void)
3510 {
3511     HWND hwnd;
3512     DWORD r;
3513     RECT bounds;
3514     LVITEMA item;
3515     static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3516     POINT pos;
3517     INT x, y, i;
3518     WORD vert;
3519     HIMAGELIST himl, himl2;
3520     HBITMAP hbmp;
3521
3522     hwnd = create_listview_control(LVS_REPORT);
3523     ok(hwnd != NULL, "failed to create a listview window\n");
3524
3525     /* LVS_REPORT with a single subitem (2 columns) */
3526     insert_column(hwnd, 0);
3527     insert_column(hwnd, 1);
3528     insert_item(hwnd, 0);
3529
3530     item.iSubItem = 0;
3531     /* the only purpose of that line is to be as long as a half item rect */
3532     item.pszText  = text;
3533     r = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
3534     expect(TRUE, r);
3535
3536     r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3537     expect(TRUE, r);
3538     r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3539     expect(TRUE, r);
3540
3541     memset(&bounds, 0, sizeof(bounds));
3542     bounds.left = LVIR_BOUNDS;
3543     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3544     expect(1, r);
3545     ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3546     ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3547     r = SendMessage(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3548     vert = HIWORD(r);
3549     ok(bounds.bottom - bounds.top == vert,
3550         "Vertical spacing inconsistent (%d != %d)\n", bounds.bottom - bounds.top, vert);
3551     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3552     expect(TRUE, r);
3553
3554     /* LVS_EX_FULLROWSELECT not set, no icons attached */
3555
3556     /* outside columns by x position - valid is [0, 199] */
3557     x = -1;
3558     y = pos.y + (bounds.bottom - bounds.top) / 2;
3559     test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3560     test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3561
3562     x = pos.x + 50; /* column half width */
3563     y = pos.y + (bounds.bottom - bounds.top) / 2;
3564     test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3565     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3566     x = pos.x + 150; /* outside column */
3567     y = pos.y + (bounds.bottom - bounds.top) / 2;
3568     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3569     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3570     y = (bounds.bottom - bounds.top) / 2;
3571     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3572     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3573     /* outside possible client rectangle (to right) */
3574     x = pos.x + 500;
3575     y = pos.y + (bounds.bottom - bounds.top) / 2;
3576     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3577     test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3578     y = (bounds.bottom - bounds.top) / 2;
3579     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3580     test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3581     /* subitem returned with -1 item too */
3582     x = pos.x + 150;
3583     y = bounds.top - vert;
3584     test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3585     test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3586     /* return values appear to underflow with negative indices */
3587     i = -2;
3588     y = y - vert;
3589     while (i > -10) {
3590         test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3591         test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3592         y = y - vert;
3593         i--;
3594     }
3595     /* parent client area is 100x100 by default */
3596     MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3597     x = pos.x + 150; /* outside column */
3598     y = pos.y + (bounds.bottom - bounds.top) / 2;
3599     test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3600     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3601     y = (bounds.bottom - bounds.top) / 2;
3602     test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
3603     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3604     /* the same with LVS_EX_FULLROWSELECT */
3605     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
3606     x = pos.x + 150; /* outside column */
3607     y = pos.y + (bounds.bottom - bounds.top) / 2;
3608     test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
3609     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3610     y = (bounds.bottom - bounds.top) / 2;
3611     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3612     MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
3613     x = pos.x + 150; /* outside column */
3614     y = pos.y + (bounds.bottom - bounds.top) / 2;
3615     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3616     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3617     y = (bounds.bottom - bounds.top) / 2;
3618     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3619     test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3620     /* outside possible client rectangle (to right) */
3621     x = pos.x + 500;
3622     y = pos.y + (bounds.bottom - bounds.top) / 2;
3623     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3624     test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3625     y = (bounds.bottom - bounds.top) / 2;
3626     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3627     test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3628     /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
3629     himl = ImageList_Create(16, 16, 0, 4, 4);
3630     ok(himl != NULL, "failed to create imagelist\n");
3631     hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3632     ok(hbmp != NULL, "failed to create bitmap\n");
3633     r = ImageList_Add(himl, hbmp, 0);
3634     ok(r == 0, "should be zero\n");
3635     hbmp = CreateBitmap(16, 16, 1, 1, NULL);
3636     ok(hbmp != NULL, "failed to create bitmap\n");
3637     r = ImageList_Add(himl, hbmp, 0);
3638     ok(r == 1, "should be one\n");
3639
3640     r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3641     expect(0, r);
3642
3643     item.mask = LVIF_IMAGE;
3644     item.iImage = 0;
3645     item.iItem = 0;
3646     item.iSubItem = 0;
3647     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3648     expect(TRUE, r);
3649     /* on state icon */
3650     x = pos.x + 8;
3651     y = pos.y + (bounds.bottom - bounds.top) / 2;
3652     test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3653     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3654     y = (bounds.bottom - bounds.top) / 2;
3655     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3656
3657     /* state icons indices are 1 based, check with valid index */
3658     item.mask = LVIF_STATE;
3659     item.state = INDEXTOSTATEIMAGEMASK(1);
3660     item.stateMask = LVIS_STATEIMAGEMASK;
3661     item.iItem = 0;
3662     item.iSubItem = 0;
3663     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3664     expect(TRUE, r);
3665     /* on state icon */
3666     x = pos.x + 8;
3667     y = pos.y + (bounds.bottom - bounds.top) / 2;
3668     test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
3669     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3670     y = (bounds.bottom - bounds.top) / 2;
3671     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
3672
3673     himl2 = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3674     ok(himl2 == himl, "should return handle\n");
3675
3676     r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3677     expect(0, r);
3678     /* on item icon */
3679     x = pos.x + 8;
3680     y = pos.y + (bounds.bottom - bounds.top) / 2;
3681     test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
3682     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3683     y = (bounds.bottom - bounds.top) / 2;
3684     test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
3685
3686     DestroyWindow(hwnd);
3687 }
3688
3689 static void test_getviewrect(void)
3690 {
3691     HWND hwnd;
3692     DWORD r;
3693     RECT rect;
3694     LVITEMA item;
3695
3696     hwnd = create_listview_control(LVS_REPORT);
3697     ok(hwnd != NULL, "failed to create a listview window\n");
3698
3699     /* empty */
3700     r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3701     expect(TRUE, r);
3702
3703     insert_column(hwnd, 0);
3704     insert_column(hwnd, 1);
3705
3706     memset(&item, 0, sizeof(item));
3707     item.iItem = 0;
3708     item.iSubItem = 0;
3709     SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3710
3711     r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3712     expect(TRUE, r);
3713     r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3714     expect(TRUE, r);
3715
3716     rect.left = rect.right = rect.top = rect.bottom = -1;
3717     r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3718     expect(TRUE, r);
3719     /* left is set to (2e31-1) - XP SP2 */
3720     expect(0, rect.right);
3721     expect(0, rect.top);
3722     expect(0, rect.bottom);
3723
3724     /* switch to LVS_ICON */
3725     SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~LVS_REPORT);
3726
3727     rect.left = rect.right = rect.top = rect.bottom = -1;
3728     r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3729     expect(TRUE, r);
3730     expect(0, rect.left);
3731     expect(0, rect.top);
3732     /* precise value differs for 2k, XP and Vista */
3733     ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3734     ok(rect.right  > 0, "Expected positive right value, got %d\n", rect.right);
3735
3736     DestroyWindow(hwnd);
3737 }
3738
3739 static void test_getitemposition(void)
3740 {
3741     HWND hwnd, header;
3742     DWORD r;
3743     POINT pt;
3744     RECT rect;
3745
3746     hwnd = create_listview_control(LVS_REPORT);
3747     ok(hwnd != NULL, "failed to create a listview window\n");
3748     header = subclass_header(hwnd);
3749
3750     /* LVS_REPORT, single item, no columns added */
3751     insert_item(hwnd, 0);
3752
3753     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3754
3755     pt.x = pt.y = -1;
3756     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3757     expect(TRUE, r);
3758     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3759
3760     /* LVS_REPORT, single item, single column */
3761     insert_column(hwnd, 0);
3762
3763     flush_sequences(sequences, NUM_MSG_SEQUENCES);
3764
3765     pt.x = pt.y = -1;
3766     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3767     expect(TRUE, r);
3768     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3769
3770     memset(&rect, 0, sizeof(rect));
3771     SendMessage(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3772     /* some padding? */
3773     expect(2, pt.x);
3774     /* offset by header height */
3775     expect(rect.bottom - rect.top, pt.y);
3776
3777     DestroyWindow(hwnd);
3778 }
3779
3780 static void test_columnscreation(void)
3781 {
3782     HWND hwnd, header;
3783     DWORD r;
3784
3785     hwnd = create_listview_control(LVS_REPORT);
3786     ok(hwnd != NULL, "failed to create a listview window\n");
3787
3788     insert_item(hwnd, 0);
3789
3790     /* headers columns aren't created automatically */
3791     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3792     ok(IsWindow(header), "Expected header handle\n");
3793     r = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
3794     expect(0, r);
3795
3796     DestroyWindow(hwnd);
3797 }
3798
3799 static void test_getitemrect(void)
3800 {
3801     HWND hwnd;
3802     HIMAGELIST himl, himl_ret;
3803     HBITMAP hbm;
3804     RECT rect;
3805     DWORD r;
3806     LVITEMA item;
3807     LVCOLUMNA col;
3808     INT order[2];
3809     POINT pt;
3810     HDC hdc;
3811
3812     /* rectangle isn't empty for empty text items */
3813     hwnd = create_listview_control(LVS_LIST);
3814     memset(&item, 0, sizeof(item));
3815     item.mask = 0;
3816     item.iItem = 0;
3817     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3818     expect(0, r);
3819     rect.left = LVIR_LABEL;
3820     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3821     expect(TRUE, r);
3822     expect(0, rect.left);
3823     expect(0, rect.top);
3824     hdc = GetDC(hwnd);
3825     todo_wine expect(((GetDeviceCaps(hdc, LOGPIXELSX) + 15) / 16) * 16, rect.right);
3826     ReleaseDC(hwnd, hdc);
3827     DestroyWindow(hwnd);
3828
3829     hwnd = create_listview_control(LVS_REPORT);
3830     ok(hwnd != NULL, "failed to create a listview window\n");
3831
3832     /* empty item */
3833     memset(&item, 0, sizeof(item));
3834     item.iItem = 0;
3835     item.iSubItem = 0;
3836     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3837     expect(0, r);
3838
3839     rect.left = LVIR_BOUNDS;
3840     rect.right = rect.top = rect.bottom = -1;
3841     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3842     expect(TRUE, r);
3843
3844     /* zero width rectangle with no padding */
3845     expect(0, rect.left);
3846     expect(0, rect.right);
3847
3848     insert_column(hwnd, 0);
3849     insert_column(hwnd, 1);
3850
3851     col.mask = LVCF_WIDTH;
3852     col.cx   = 50;
3853     r = SendMessage(hwnd, LVM_SETCOLUMN, 0, (LPARAM)&col);
3854     expect(TRUE, r);
3855
3856     col.mask = LVCF_WIDTH;
3857     col.cx   = 100;
3858     r = SendMessage(hwnd, LVM_SETCOLUMN, 1, (LPARAM)&col);
3859     expect(TRUE, r);
3860
3861     rect.left = LVIR_BOUNDS;
3862     rect.right = rect.top = rect.bottom = -1;
3863     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3864     expect(TRUE, r);
3865
3866     /* still no left padding */
3867     expect(0, rect.left);
3868     expect(150, rect.right);
3869
3870     rect.left = LVIR_SELECTBOUNDS;
3871     rect.right = rect.top = rect.bottom = -1;
3872     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3873     expect(TRUE, r);
3874     /* padding */
3875     expect(2, rect.left);
3876
3877     rect.left = LVIR_LABEL;
3878     rect.right = rect.top = rect.bottom = -1;
3879     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3880     expect(TRUE, r);
3881     /* padding, column width */
3882     expect(2, rect.left);
3883     expect(50, rect.right);
3884
3885     /* no icons attached */
3886     rect.left = LVIR_ICON;
3887     rect.right = rect.top = rect.bottom = -1;
3888     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3889     expect(TRUE, r);
3890     /* padding */
3891     expect(2, rect.left);
3892     expect(2, rect.right);
3893
3894     /* change order */
3895     order[0] = 1; order[1] = 0;
3896     r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3897     expect(TRUE, r);
3898     pt.x = -1;
3899     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3900     expect(TRUE, r);
3901     /* 1 indexed column width + padding */
3902     expect(102, pt.x);
3903     /* rect is at zero too */
3904     rect.left = LVIR_BOUNDS;
3905     rect.right = rect.top = rect.bottom = -1;
3906     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3907     expect(TRUE, r);
3908     expect(0, rect.left);
3909     /* just width sum */
3910     expect(150, rect.right);
3911
3912     rect.left = LVIR_SELECTBOUNDS;
3913     rect.right = rect.top = rect.bottom = -1;
3914     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3915     expect(TRUE, r);
3916     /* column width + padding */
3917     expect(102, rect.left);
3918
3919     /* back to initial order */
3920     order[0] = 0; order[1] = 1;
3921     r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3922     expect(TRUE, r);
3923
3924     /* state icons */
3925     himl = ImageList_Create(16, 16, 0, 2, 2);
3926     ok(himl != NULL, "failed to create imagelist\n");
3927     hbm = CreateBitmap(16, 16, 1, 1, NULL);
3928     ok(hbm != NULL, "failed to create bitmap\n");
3929     r = ImageList_Add(himl, hbm, 0);
3930     expect(0, r);
3931     hbm = CreateBitmap(16, 16, 1, 1, NULL);
3932     ok(hbm != NULL, "failed to create bitmap\n");
3933     r = ImageList_Add(himl, hbm, 0);
3934     expect(1, r);
3935
3936     r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3937     expect(0, r);
3938
3939     item.mask = LVIF_STATE;
3940     item.state = INDEXTOSTATEIMAGEMASK(1);
3941     item.stateMask = LVIS_STATEIMAGEMASK;
3942     item.iItem = 0;
3943     item.iSubItem = 0;
3944     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3945     expect(TRUE, r);
3946
3947     /* icon bounds */
3948     rect.left = LVIR_ICON;
3949     rect.right = rect.top = rect.bottom = -1;
3950     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3951     expect(TRUE, r);
3952     /* padding + stateicon width */
3953     expect(18, rect.left);
3954     expect(18, rect.right);
3955     /* label bounds */
3956     rect.left = LVIR_LABEL;
3957     rect.right = rect.top = rect.bottom = -1;
3958     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3959     expect(TRUE, r);
3960     /* padding + stateicon width -> column width */
3961     expect(18, rect.left);
3962     expect(50, rect.right);
3963
3964     himl_ret = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
3965     ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
3966
3967     r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3968     expect(0, r);
3969
3970     item.mask = LVIF_STATE | LVIF_IMAGE;
3971     item.iImage = 1;
3972     item.state = 0;
3973     item.stateMask = ~0;
3974     item.iItem = 0;
3975     item.iSubItem = 0;
3976     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3977     expect(TRUE, r);
3978
3979     /* icon bounds */
3980     rect.left = LVIR_ICON;
3981     rect.right = rect.top = rect.bottom = -1;
3982     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3983     expect(TRUE, r);
3984     /* padding, icon width */
3985     expect(2, rect.left);
3986     expect(18, rect.right);
3987     /* label bounds */
3988     rect.left = LVIR_LABEL;
3989     rect.right = rect.top = rect.bottom = -1;
3990     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3991     expect(TRUE, r);
3992     /* padding + icon width -> column width */
3993     expect(18, rect.left);
3994     expect(50, rect.right);
3995
3996     /* select bounds */
3997     rect.left = LVIR_SELECTBOUNDS;
3998     rect.right = rect.top = rect.bottom = -1;
3999     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4000     expect(TRUE, r);
4001     /* padding, column width */
4002     expect(2, rect.left);
4003     expect(50, rect.right);
4004
4005     /* try with indentation */
4006     item.mask = LVIF_INDENT;
4007     item.iIndent = 1;
4008     item.iItem = 0;
4009     item.iSubItem = 0;
4010     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
4011     expect(TRUE, r);
4012
4013     /* bounds */
4014     rect.left = LVIR_BOUNDS;
4015     rect.right = rect.top = rect.bottom = -1;
4016     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4017     expect(TRUE, r);
4018     /* padding + 1 icon width, column width */
4019     expect(0, rect.left);
4020     expect(150, rect.right);
4021
4022     /* select bounds */
4023     rect.left = LVIR_SELECTBOUNDS;
4024     rect.right = rect.top = rect.bottom = -1;
4025     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4026     expect(TRUE, r);
4027     /* padding + 1 icon width, column width */
4028     expect(2 + 16, rect.left);
4029     expect(50, rect.right);
4030
4031     /* label bounds */
4032     rect.left = LVIR_LABEL;
4033     rect.right = rect.top = rect.bottom = -1;
4034     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4035     expect(TRUE, r);
4036     /* padding + 2 icon widths, column width */
4037     expect(2 + 16*2, rect.left);
4038     expect(50, rect.right);
4039
4040     /* icon bounds */
4041     rect.left = LVIR_ICON;
4042     rect.right = rect.top = rect.bottom = -1;
4043     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4044     expect(TRUE, r);
4045     /* padding + 1 icon width indentation, icon width */
4046     expect(2 + 16, rect.left);
4047     expect(34, rect.right);
4048
4049     DestroyWindow(hwnd);
4050 }
4051
4052 static void test_editbox(void)
4053 {
4054     static CHAR testitemA[]  = "testitem";
4055     static CHAR testitem1A[] = "testitem_quitelongname";
4056     static CHAR testitem2A[] = "testITEM_quitelongname";
4057     static CHAR buffer[25];
4058     HWND hwnd, hwndedit, hwndedit2, header;
4059     LVITEMA item;
4060     INT r;
4061
4062     hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4063     ok(hwnd != NULL, "failed to create a listview window\n");
4064
4065     insert_column(hwnd, 0);
4066
4067     memset(&item, 0, sizeof(item));
4068     item.mask = LVIF_TEXT;
4069     item.pszText = testitemA;
4070     item.iItem = 0;
4071     item.iSubItem = 0;
4072     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4073     expect(0, r);
4074
4075     /* test notifications without edit created */
4076     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4077     r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4078     expect(0, r);
4079     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4080                 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4081     /* same thing but with valid window */
4082     hwndedit = CreateWindowA("Edit", "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4083                 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4084     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4085     r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4086     expect(0, r);
4087     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4088                 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4089     DestroyWindow(hwndedit);
4090
4091     /* setting focus is necessary */
4092     SetFocus(hwnd);
4093     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4094     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4095
4096     /* test children Z-order after Edit box created */
4097     header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4098     ok(IsWindow(header), "Expected header to be created\n");
4099     ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4100     ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4101
4102     /* modify initial string */
4103     r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4104     expect(TRUE, r);
4105
4106     /* edit window is resized and repositioned,
4107        check again for Z-order - it should be preserved */
4108     ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4109     ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4110
4111     /* return focus to listview */
4112     SetFocus(hwnd);
4113
4114     memset(&item, 0, sizeof(item));
4115     item.mask = LVIF_TEXT;
4116     item.pszText = buffer;
4117     item.cchTextMax = sizeof(buffer);
4118     item.iItem = 0;
4119     item.iSubItem = 0;
4120     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4121     expect(TRUE, r);
4122
4123     ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4124
4125     /* send LVM_EDITLABEL on already created edit */
4126     SetFocus(hwnd);
4127     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4128     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4129     /* focus will be set to edit */
4130     ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4131     hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4132     ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4133
4134     /* creating label disabled when control isn't focused */
4135     SetFocus(0);
4136     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4137     todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4138
4139     /* check EN_KILLFOCUS handling */
4140     memset(&item, 0, sizeof(item));
4141     item.pszText = testitemA;
4142     item.iItem = 0;
4143     item.iSubItem = 0;
4144     r = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4145     expect(TRUE, r);
4146
4147     SetFocus(hwnd);
4148     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4149     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4150     /* modify edit and notify control that it lost focus */
4151     r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4152     expect(TRUE, r);
4153     g_editbox_disp_info.item.pszText = NULL;
4154     r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4155     expect(0, r);
4156     ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4157
4158     memset(&item, 0, sizeof(item));
4159     item.pszText = buffer;
4160     item.cchTextMax = sizeof(buffer);
4161     item.iItem = 0;
4162     item.iSubItem = 0;
4163     r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4164     expect(lstrlen(item.pszText), r);
4165     ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4166     ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4167
4168     /* change item name to differ in casing only */
4169     SetFocus(hwnd);
4170     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4171     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4172     /* modify edit and notify control that it lost focus */
4173     r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4174     expect(TRUE, r);
4175     g_editbox_disp_info.item.pszText = NULL;
4176     r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4177     expect(0, r);
4178     ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4179
4180     memset(&item, 0, sizeof(item));
4181     item.pszText = buffer;
4182     item.cchTextMax = sizeof(buffer);
4183     item.iItem = 0;
4184     item.iSubItem = 0;
4185     r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4186     expect(lstrlen(item.pszText), r);
4187     ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4188     ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4189
4190     /* end edit without saving */
4191     SetFocus(hwnd);
4192     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4193     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4194     r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4195     expect(0, r);
4196     ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4197                 "edit box - end edit, no change, escape", TRUE);
4198     /* end edit with saving */
4199     SetFocus(hwnd);
4200     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4201     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4202     r = SendMessage(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4203     expect(0, r);
4204     ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4205                 "edit box - end edit, no change, return", TRUE);
4206
4207     memset(&item, 0, sizeof(item));
4208     item.pszText = buffer;
4209     item.cchTextMax = sizeof(buffer);
4210     item.iItem = 0;
4211     item.iSubItem = 0;
4212     r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4213     expect(lstrlen(item.pszText), r);
4214     ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4215
4216     /* LVM_EDITLABEL with -1 destroys current edit */
4217     hwndedit = (HWND)SendMessage(hwnd, LVM_GETEDITCONTROL, 0, 0);
4218     ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4219     /* no edit present */
4220     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
4221     ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4222     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4223     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4224     /* edit present */
4225     ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4226     hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
4227     ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4228     ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4229     ok(GetFocus() == hwnd, "Expected List to be focused\n");
4230     /* check another negative value */
4231     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4232     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4233     ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4234     hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -2, 0);
4235     ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4236     ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4237     ok(GetFocus() == hwnd, "Expected List to be focused\n");
4238     /* and value greater than max item index */
4239     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4240     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4241     ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4242     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
4243     hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, r, 0);
4244     ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4245     ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4246     ok(GetFocus() == hwnd, "Expected List to be focused\n");
4247
4248     /* messaging tests */
4249     SetFocus(hwnd);
4250     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4251     blockEdit = FALSE;
4252     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4253     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4254     /* testing only sizing messages */
4255     ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4256                 "edit box create - sizing", FALSE);
4257
4258     /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4259     SetFocus(hwnd);
4260     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4261     ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4262     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4263     r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4264     expect(0, r);
4265     ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4266                 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4267
4268     DestroyWindow(hwnd);
4269 }
4270
4271 static void test_notifyformat(void)
4272 {
4273     HWND hwnd, header;
4274     DWORD r;
4275
4276     hwnd = create_listview_control(LVS_REPORT);
4277     ok(hwnd != NULL, "failed to create a listview window\n");
4278
4279     /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4280        CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4281     r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4282     expect(0, r);
4283     SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4284     /* set */
4285     r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4286     expect(0, r);
4287     r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4288     if (r == 1)
4289     {
4290         r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4291         expect(1, r);
4292         r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4293         expect(0, r);
4294     }
4295     else
4296     {
4297         win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
4298         DestroyWindow(hwnd);
4299         return;
4300     }
4301
4302     DestroyWindow(hwnd);
4303
4304     /* test failure in parent WM_NOTIFYFORMAT  */
4305     notifyFormat = 0;
4306     hwnd = create_listview_control(LVS_REPORT);
4307     ok(hwnd != NULL, "failed to create a listview window\n");
4308     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4309     ok(IsWindow(header), "expected header to be created\n");
4310     r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4311     expect(0, r);
4312     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4313     ok( r == 1, "Expected 1, got %d\n", r );
4314     r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4315     ok(r != 0, "Expected valid format\n");
4316
4317     notifyFormat = NFR_UNICODE;
4318     r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4319     expect(NFR_UNICODE, r);
4320     r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4321     expect(1, r);
4322     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4323     ok( r == 1, "Expected 1, got %d\n", r );
4324
4325     notifyFormat = NFR_ANSI;
4326     r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4327     expect(NFR_ANSI, r);
4328     r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4329     expect(0, r);
4330     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4331     ok( r == 1, "Expected 1, got %d\n", r );
4332
4333     DestroyWindow(hwnd);
4334
4335     hwndparentW = create_parent_window(TRUE);
4336     ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4337     if (!IsWindow(hwndparentW))  return;
4338
4339     notifyFormat = -1;
4340     hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4341     ok(hwnd != NULL, "failed to create a listview window\n");
4342     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4343     ok(IsWindow(header), "expected header to be created\n");
4344     r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4345     expect(1, r);
4346     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4347     expect(1, r);
4348     DestroyWindow(hwnd);
4349     /* receiving error code defaulting to ansi */
4350     notifyFormat = 0;
4351     hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4352     ok(hwnd != NULL, "failed to create a listview window\n");
4353     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4354     ok(IsWindow(header), "expected header to be created\n");
4355     r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4356     expect(0, r);
4357     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4358     expect(1, r);
4359     DestroyWindow(hwnd);
4360     /* receiving ansi code from unicode window, use it */
4361     notifyFormat = NFR_ANSI;
4362     hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4363     ok(hwnd != NULL, "failed to create a listview window\n");
4364     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4365     ok(IsWindow(header), "expected header to be created\n");
4366     r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4367     expect(0, r);
4368     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4369     expect(1, r);
4370     DestroyWindow(hwnd);
4371     /* unicode listview with ansi parent window */
4372     notifyFormat = -1;
4373     hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4374     ok(hwnd != NULL, "failed to create a listview window\n");
4375     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4376     ok(IsWindow(header), "expected header to be created\n");
4377     r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4378     expect(0, r);
4379     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4380     expect(1, r);
4381     DestroyWindow(hwnd);
4382     /* unicode listview with ansi parent window, return error code */
4383     notifyFormat = 0;
4384     hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4385     ok(hwnd != NULL, "failed to create a listview window\n");
4386     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4387     ok(IsWindow(header), "expected header to be created\n");
4388     r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4389     expect(0, r);
4390     r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
4391     expect(1, r);
4392     DestroyWindow(hwnd);
4393
4394     DestroyWindow(hwndparentW);
4395 }
4396
4397 static void test_indentation(void)
4398 {
4399     HWND hwnd;
4400     LVITEMA item;
4401     DWORD r;
4402
4403     hwnd = create_listview_control(LVS_REPORT);
4404     ok(hwnd != NULL, "failed to create a listview window\n");
4405
4406     memset(&item, 0, sizeof(item));
4407     item.mask = LVIF_INDENT;
4408     item.iItem = 0;
4409     item.iIndent = I_INDENTCALLBACK;
4410     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4411     expect(0, r);
4412
4413     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4414
4415     item.iItem = 0;
4416     item.mask = LVIF_INDENT;
4417     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
4418     expect(TRUE, r);
4419
4420     ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4421                 "get indent dispinfo", FALSE);
4422
4423     DestroyWindow(hwnd);
4424 }
4425
4426 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
4427 {
4428     return 0;
4429 }
4430
4431 static BOOL is_below_comctl_5(void)
4432 {
4433     HWND hwnd;
4434     BOOL ret;
4435
4436     hwnd = create_listview_control(LVS_REPORT);
4437     ok(hwnd != NULL, "failed to create a listview window\n");
4438     insert_item(hwnd, 0);
4439
4440     ret = SendMessage(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
4441
4442     DestroyWindow(hwnd);
4443
4444     return !ret;
4445 }
4446
4447 static void test_get_set_view(void)
4448 {
4449     HWND hwnd;
4450     DWORD ret;
4451     DWORD_PTR style;
4452
4453     /* test style->view mapping */
4454     hwnd = create_listview_control(LVS_REPORT);
4455     ok(hwnd != NULL, "failed to create a listview window\n");
4456
4457     ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4458     expect(LV_VIEW_DETAILS, ret);
4459
4460     style = GetWindowLongPtr(hwnd, GWL_STYLE);
4461     /* LVS_ICON == 0 */
4462     SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4463     ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4464     expect(LV_VIEW_ICON, ret);
4465
4466     style = GetWindowLongPtr(hwnd, GWL_STYLE);
4467     SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4468     ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4469     expect(LV_VIEW_SMALLICON, ret);
4470
4471     style = GetWindowLongPtr(hwnd, GWL_STYLE);
4472     SetWindowLongPtr(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4473     ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
4474     expect(LV_VIEW_LIST, ret);
4475
4476     /* switching view doesn't touch window style */
4477     ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4478     expect(1, ret);
4479     style = GetWindowLongPtr(hwnd, GWL_STYLE);
4480     ok(style & LVS_LIST, "Expected style to be preserved\n");
4481     ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4482     expect(1, ret);
4483     style = GetWindowLongPtr(hwnd, GWL_STYLE);
4484     ok(style & LVS_LIST, "Expected style to be preserved\n");
4485     ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4486     expect(1, ret);
4487     style = GetWindowLongPtr(hwnd, GWL_STYLE);
4488     ok(style & LVS_LIST, "Expected style to be preserved\n");
4489
4490     DestroyWindow(hwnd);
4491 }
4492
4493 static void test_canceleditlabel(void)
4494 {
4495     HWND hwnd, hwndedit;
4496     DWORD ret;
4497     CHAR buff[10];
4498     LVITEMA itema;
4499     static CHAR test[] = "test";
4500     static const CHAR test1[] = "test1";
4501
4502     hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4503     ok(hwnd != NULL, "failed to create a listview window\n");
4504
4505     insert_item(hwnd, 0);
4506
4507     /* try without edit created */
4508     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4509     ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4510     expect(TRUE, ret);
4511     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4512                 "cancel edit label without edit", FALSE);
4513
4514     /* cancel without data change */
4515     SetFocus(hwnd);
4516     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4517     ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4518     ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4519     expect(TRUE, ret);
4520     ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4521
4522     /* cancel after data change */
4523     memset(&itema, 0, sizeof(itema));
4524     itema.pszText = test;
4525     ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
4526     expect(TRUE, ret);
4527     SetFocus(hwnd);
4528     hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
4529     ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4530     ret = SetWindowText(hwndedit, test1);
4531     expect(1, ret);
4532     ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4533     expect(TRUE, ret);
4534     ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4535     memset(&itema, 0, sizeof(itema));
4536     itema.pszText = buff;
4537     itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
4538     ret = SendMessage(hwnd, LVM_GETITEMTEXT, 0, (LPARAM)&itema);
4539     expect(5, ret);
4540     ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4541
4542     DestroyWindow(hwnd);
4543 }
4544
4545 static void test_mapidindex(void)
4546 {
4547     HWND hwnd;
4548     INT ret;
4549
4550     /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4551     hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4552     ok(hwnd != NULL, "failed to create a listview window\n");
4553     insert_item(hwnd, 0);
4554     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4555     expect(-1, ret);
4556     DestroyWindow(hwnd);
4557
4558     hwnd = create_listview_control(LVS_REPORT);
4559     ok(hwnd != NULL, "failed to create a listview window\n");
4560
4561     /* LVM_MAPINDEXTOID with invalid index */
4562     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4563     expect(-1, ret);
4564
4565     insert_item(hwnd, 0);
4566     insert_item(hwnd, 1);
4567
4568     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0);
4569     expect(-1, ret);
4570     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0);
4571     expect(-1, ret);
4572
4573     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4574     expect(0, ret);
4575     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
4576     expect(1, ret);
4577     /* remove 0 indexed item, id retained */
4578     SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
4579     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
4580     expect(1, ret);
4581     /* new id starts from previous value */
4582     insert_item(hwnd, 1);
4583     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
4584     expect(2, ret);
4585
4586     /* get index by id */
4587     ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4588     expect(-1, ret);
4589     ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4590     expect(-1, ret);
4591     ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4592     expect(0, ret);
4593     ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4594     expect(1, ret);
4595
4596     DestroyWindow(hwnd);
4597 }
4598
4599 static void test_getitemspacing(void)
4600 {
4601     HWND hwnd;
4602     DWORD ret;
4603     INT cx, cy;
4604     HIMAGELIST himl40, himl80;
4605
4606     cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4607     cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4608
4609     /* LVS_ICON */
4610     hwnd = create_listview_control(LVS_ICON);
4611     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4612     expect(cx, LOWORD(ret));
4613     expect(cy, HIWORD(ret));
4614
4615     /* now try with icons */
4616     himl40 = ImageList_Create(40, 40, 0, 4, 4);
4617     ok(himl40 != NULL, "failed to create imagelist\n");
4618     himl80 = ImageList_Create(80, 80, 0, 4, 4);
4619     ok(himl80 != NULL, "failed to create imagelist\n");
4620     ret = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4621     expect(0, ret);
4622
4623     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4624     /* spacing + icon size returned */
4625     expect(cx + 40, LOWORD(ret));
4626     expect(cy + 40, HIWORD(ret));
4627     /* try changing icon size */
4628     SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4629
4630     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4631     /* spacing + icon size returned */
4632     expect(cx + 80, LOWORD(ret));
4633     expect(cy + 80, HIWORD(ret));
4634
4635     /* set own icon spacing */
4636     ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4637     expect(cx + 80, LOWORD(ret));
4638     expect(cy + 80, HIWORD(ret));
4639
4640     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4641     /* set size returned */
4642     expect(100, LOWORD(ret));
4643     expect(100, HIWORD(ret));
4644
4645     /* now change image list - icon spacing should be unaffected */
4646     SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4647
4648     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4649     /* set size returned */
4650     expect(100, LOWORD(ret));
4651     expect(100, HIWORD(ret));
4652
4653     /* spacing = 0 - keep previous value */
4654     ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
4655     expect(100, LOWORD(ret));
4656     expect(100, HIWORD(ret));
4657
4658     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4659     expect(100, LOWORD(ret));
4660
4661     expect(0xFFFF, HIWORD(ret));
4662
4663     if (sizeof(void*) == 8)
4664     {
4665         /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
4666         ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
4667         expect(100, LOWORD(ret));
4668         expect(0xFFFF, HIWORD(ret));
4669
4670         ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, -1);
4671         expect(0xFFFF, LOWORD(ret));
4672         expect(0xFFFF, HIWORD(ret));
4673     }
4674     else
4675     {
4676         ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, -1);
4677         expect(100, LOWORD(ret));
4678         expect(0xFFFF, HIWORD(ret));
4679     }
4680     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4681     /* spacing + icon size returned */
4682     expect(cx + 40, LOWORD(ret));
4683     expect(cy + 40, HIWORD(ret));
4684
4685     SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4686     ImageList_Destroy(himl80);
4687     DestroyWindow(hwnd);
4688     /* LVS_SMALLICON */
4689     hwnd = create_listview_control(LVS_SMALLICON);
4690     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4691     expect(cx, LOWORD(ret));
4692     expect(cy, HIWORD(ret));
4693
4694     /* spacing does not depend on selected view type */
4695     ret = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4696     expect(0, ret);
4697
4698     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4699     /* spacing + icon size returned */
4700     expect(cx + 40, LOWORD(ret));
4701     expect(cy + 40, HIWORD(ret));
4702
4703     SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
4704     ImageList_Destroy(himl40);
4705     DestroyWindow(hwnd);
4706     /* LVS_REPORT */
4707     hwnd = create_listview_control(LVS_REPORT);
4708     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4709     expect(cx, LOWORD(ret));
4710     expect(cy, HIWORD(ret));
4711
4712     DestroyWindow(hwnd);
4713     /* LVS_LIST */
4714     hwnd = create_listview_control(LVS_LIST);
4715     ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4716     expect(cx, LOWORD(ret));
4717     expect(cy, HIWORD(ret));
4718
4719     DestroyWindow(hwnd);
4720 }
4721
4722 static void test_getcolumnwidth(void)
4723 {
4724     HWND hwnd;
4725     INT ret;
4726     DWORD_PTR style;
4727     LVCOLUMNA col;
4728     LVITEMA itema;
4729     HDC hdc;
4730
4731     /* default column width */
4732     hwnd = create_listview_control(LVS_ICON);
4733     ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4734     expect(0, ret);
4735     style = GetWindowLong(hwnd, GWL_STYLE);
4736     SetWindowLong(hwnd, GWL_STYLE, style | LVS_LIST);
4737     ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4738     todo_wine expect(8, ret);
4739     style = GetWindowLong(hwnd, GWL_STYLE) & ~LVS_LIST;
4740     SetWindowLong(hwnd, GWL_STYLE, style | LVS_REPORT);
4741     col.mask = 0;
4742     ret = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
4743     expect(0, ret);
4744     ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4745     expect(10, ret);
4746     DestroyWindow(hwnd);
4747
4748     /* default column width with item added */
4749     hwnd = create_listview_control(LVS_LIST);
4750     memset(&itema, 0, sizeof(itema));
4751     SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
4752     ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
4753     hdc = GetDC(hwnd);
4754     todo_wine expect(((GetDeviceCaps(hdc, LOGPIXELSX) + 15) / 16) * 16, ret);
4755     ReleaseDC(hwnd, hdc);
4756     DestroyWindow(hwnd);
4757 }
4758
4759 static void test_scrollnotify(void)
4760 {
4761     HWND hwnd;
4762     DWORD ret;
4763
4764     hwnd = create_listview_control(LVS_REPORT);
4765
4766     insert_column(hwnd, 0);
4767     insert_column(hwnd, 1);
4768     insert_item(hwnd, 0);
4769
4770     /* make it scrollable - resize */
4771     ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4772     expect(TRUE, ret);
4773     ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
4774     expect(TRUE, ret);
4775
4776     /* try with dummy call */
4777     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4778     ret = SendMessage(hwnd, LVM_SCROLL, 0, 0);
4779     expect(TRUE, ret);
4780     ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4781                 "scroll notify 1", TRUE);
4782
4783     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4784     ret = SendMessage(hwnd, LVM_SCROLL, 1, 0);
4785     expect(TRUE, ret);
4786     ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4787                 "scroll notify 2", TRUE);
4788
4789     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4790     ret = SendMessage(hwnd, LVM_SCROLL, 1, 1);
4791     expect(TRUE, ret);
4792     ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
4793                 "scroll notify 3", TRUE);
4794
4795     DestroyWindow(hwnd);
4796 }
4797
4798 static void test_LVS_EX_TRANSPARENTBKGND(void)
4799 {
4800     HWND hwnd;
4801     DWORD ret;
4802     HDC hdc;
4803
4804     hwnd = create_listview_control(LVS_REPORT);
4805
4806     ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4807     expect(TRUE, ret);
4808
4809     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4810                                                     LVS_EX_TRANSPARENTBKGND);
4811
4812     ret = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
4813     if (ret != CLR_NONE)
4814     {
4815         win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4816         DestroyWindow(hwnd);
4817         return;
4818     }
4819
4820     /* try to set some back color and check this style bit */
4821     ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4822     expect(TRUE, ret);
4823     ret = SendMessage(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4824     ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4825
4826     /* now test what this style actually does */
4827     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4828                                                     LVS_EX_TRANSPARENTBKGND);
4829
4830     hdc = GetWindowDC(hwndparent);
4831
4832     flush_sequences(sequences, NUM_MSG_SEQUENCES);
4833     SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4834     ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4835                 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4836
4837     ReleaseDC(hwndparent, hdc);
4838
4839     DestroyWindow(hwnd);
4840 }
4841
4842 static void test_approximate_viewrect(void)
4843 {
4844     HWND hwnd;
4845     DWORD ret;
4846     HIMAGELIST himl;
4847     HBITMAP hbmp;
4848     LVITEMA itema;
4849     static CHAR test[] = "abracadabra, a very long item label";
4850
4851     hwnd = create_listview_control(LVS_ICON);
4852     himl = ImageList_Create(40, 40, 0, 4, 4);
4853     ok(himl != NULL, "failed to create imagelist\n");
4854     hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4855     ok(hbmp != NULL, "failed to create bitmap\n");
4856     ret = ImageList_Add(himl, hbmp, 0);
4857     expect(0, ret);
4858     ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4859     expect(0, ret);
4860
4861     itema.mask = LVIF_IMAGE;
4862     itema.iImage = 0;
4863     itema.iItem = 0;
4864     itema.iSubItem = 0;
4865     ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
4866     expect(0, ret);
4867
4868     ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
4869     if (ret == 0)
4870     {
4871         /* version 4.0 */
4872         win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
4873         return;
4874     }
4875
4876     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4877     expect(MAKELONG(77,827), ret);
4878
4879     ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
4880     ok(ret != 0, "got 0\n");
4881
4882     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4883     expect(MAKELONG(102,302), ret);
4884
4885     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4886     expect(MAKELONG(52,52), ret);
4887
4888     itema.pszText = test;
4889     ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
4890     expect(TRUE, ret);
4891     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4892     expect(MAKELONG(52,52), ret);
4893
4894     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
4895     expect(MAKELONG(52,2), ret);
4896     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
4897     expect(MAKELONG(52,52), ret);
4898     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
4899     expect(MAKELONG(102,52), ret);
4900     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
4901     expect(MAKELONG(102,102), ret);
4902     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
4903     expect(MAKELONG(102,102), ret);
4904     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
4905     expect(MAKELONG(102,152), ret);
4906     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
4907     expect(MAKELONG(102,152), ret);
4908     ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
4909     expect(MAKELONG(152,152), ret);
4910
4911     DestroyWindow(hwnd);
4912 }
4913
4914 static void test_finditem(void)
4915 {
4916     LVFINDINFOA fi;
4917     static char f[5];
4918     HWND hwnd;
4919     INT r;
4920
4921     hwnd = create_listview_control(LVS_REPORT);
4922     insert_item(hwnd, 0);
4923
4924     memset(&fi, 0, sizeof(fi));
4925
4926     /* full string search, inserted text was "foo" */
4927     strcpy(f, "foo");
4928     fi.flags = LVFI_STRING;
4929     fi.psz = f;
4930     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4931     expect(0, r);
4932     /* partial string search, inserted text was "foo" */
4933     strcpy(f, "fo");
4934     fi.flags = LVFI_STRING | LVFI_PARTIAL;
4935     fi.psz = f;
4936     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4937     expect(0, r);
4938     /* partial string search, part after start char */
4939     strcpy(f, "oo");
4940     fi.flags = LVFI_STRING | LVFI_PARTIAL;
4941     fi.psz = f;
4942     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4943     expect(-1, r);
4944
4945     /* try with LVFI_SUBSTRING */
4946     strcpy(f, "fo");
4947     fi.flags = LVFI_SUBSTRING;
4948     fi.psz = f;
4949     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4950     if (r == -1)
4951     {
4952         win_skip("LVFI_SUBSTRING not supported\n");
4953         DestroyWindow(hwnd);
4954         return;
4955     }
4956     expect(0, r);
4957     strcpy(f, "f");
4958     fi.flags = LVFI_SUBSTRING;
4959     fi.psz = f;
4960     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4961     expect(0, r);
4962     strcpy(f, "o");
4963     fi.flags = LVFI_SUBSTRING;
4964     fi.psz = f;
4965     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4966     expect(-1, r);
4967
4968     strcpy(f, "f");
4969     fi.flags = LVFI_SUBSTRING | LVFI_STRING;
4970     fi.psz = f;
4971     r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4972     expect(0, r);
4973
4974     DestroyWindow(hwnd);
4975 }
4976
4977 static void test_LVS_EX_HEADERINALLVIEWS(void)
4978 {
4979     HWND hwnd, header;
4980     DWORD style;
4981
4982     hwnd = create_listview_control(LVS_ICON);
4983
4984     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4985                                                     LVS_EX_HEADERINALLVIEWS);
4986
4987     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4988     if (!IsWindow(header))
4989     {
4990         win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
4991         DestroyWindow(hwnd);
4992         return;
4993     }
4994
4995     /* LVS_NOCOLUMNHEADER works as before */
4996     style = GetWindowLongA(hwnd, GWL_STYLE);
4997     SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
4998     style = GetWindowLongA(header, GWL_STYLE);
4999     ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5000     style = GetWindowLongA(hwnd, GWL_STYLE);
5001     SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5002     style = GetWindowLongA(header, GWL_STYLE);
5003     ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5004
5005     /* try to remove style */
5006     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5007     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
5008     ok(IsWindow(header), "Expected header to be created\n");
5009     style = GetWindowLongA(header, GWL_STYLE);
5010     ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5011
5012     DestroyWindow(hwnd);
5013
5014     /* check other styles */
5015     hwnd = create_listview_control(LVS_LIST);
5016     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5017                                                     LVS_EX_HEADERINALLVIEWS);
5018     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
5019     ok(IsWindow(header), "Expected header to be created\n");
5020     DestroyWindow(hwnd);
5021
5022     hwnd = create_listview_control(LVS_SMALLICON);
5023     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5024                                                     LVS_EX_HEADERINALLVIEWS);
5025     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
5026     ok(IsWindow(header), "Expected header to be created\n");
5027     DestroyWindow(hwnd);
5028
5029     hwnd = create_listview_control(LVS_REPORT);
5030     SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5031                                                     LVS_EX_HEADERINALLVIEWS);
5032     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
5033     ok(IsWindow(header), "Expected header to be created\n");
5034     DestroyWindow(hwnd);
5035 }
5036
5037 static void test_hover(void)
5038 {
5039     HWND hwnd;
5040     DWORD r;
5041
5042     hwnd = create_listview_control(LVS_ICON);
5043
5044     /* test WM_MOUSEHOVER forwarding */
5045     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5046     r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
5047     expect(0, r);
5048     ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5049     g_block_hover = TRUE;
5050     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5051     r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
5052     expect(0, r);
5053     ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5054     g_block_hover = FALSE;
5055
5056     r = SendMessage(hwnd, LVM_SETHOVERTIME, 0, 500);
5057     expect(HOVER_DEFAULT, r);
5058     r = SendMessage(hwnd, LVM_GETHOVERTIME, 0, 0);
5059     expect(500, r);
5060
5061     DestroyWindow(hwnd);
5062 }
5063
5064 static void test_destroynotify(void)
5065 {
5066     HWND hwnd;
5067
5068     hwnd = create_listview_control(LVS_REPORT);
5069     ok(hwnd != NULL, "failed to create listview window\n");
5070
5071     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5072     DestroyWindow(hwnd);
5073     ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5074 }
5075
5076 static void test_header_notification(void)
5077 {
5078     static char textA[] = "newtext";
5079     HWND list, header;
5080     HDITEMA item;
5081     NMHEADER nmh;
5082     LVCOLUMNA col;
5083     DWORD ret;
5084     BOOL r;
5085
5086     list = create_listview_control(LVS_REPORT);
5087     ok(list != NULL, "failed to create listview window\n");
5088
5089     memset(&col, 0, sizeof(col));
5090     col.mask = LVCF_WIDTH;
5091     col.cx = 100;
5092     ret = SendMessage(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5093     expect(0, ret);
5094
5095     /* check list parent notification after header item changed,
5096        this test should be placed before header subclassing to avoid
5097        Listview -> Header messages to be logged */
5098     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5099
5100     col.mask = LVCF_TEXT;
5101     col.pszText = textA;
5102     r = SendMessage(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5103     expect(TRUE, r);
5104
5105     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5106                 "header notify, listview", FALSE);
5107     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5108                 "header notify, parent", FALSE);
5109
5110     header = subclass_header(list);
5111
5112     ret = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
5113     expect(1, ret);
5114
5115     memset(&item, 0, sizeof(item));
5116     item.mask = HDI_WIDTH;
5117     ret = SendMessage(header, HDM_GETITEMA, 0, (LPARAM)&item);
5118     expect(1, ret);
5119     expect(100, item.cxy);
5120
5121     nmh.hdr.hwndFrom = header;
5122     nmh.hdr.idFrom = GetWindowLongPtr(header, GWLP_ID);
5123     nmh.hdr.code = HDN_ITEMCHANGEDA;
5124     nmh.iItem = 0;
5125     nmh.iButton = 0;
5126     item.mask = HDI_WIDTH;
5127     item.cxy = 50;
5128     nmh.pitem = &item;
5129     ret = SendMessage(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5130     expect(0, ret);
5131
5132     DestroyWindow(list);
5133 }
5134
5135 static void test_header_notification2(void)
5136 {
5137     static char textA[] = "newtext";
5138     HWND list, header;
5139     HDITEMW itemW;
5140     NMHEADERW nmhdr;
5141     LVCOLUMNA col;
5142     DWORD ret;
5143     WCHAR buffer[100];
5144     struct message parent_header_notify_seq[] = {
5145         { WM_NOTIFY, sent|id, 0, 0, 0 },
5146         { 0 }
5147     };
5148
5149     list = create_listview_control(LVS_REPORT);
5150     ok(list != NULL, "failed to create listview window\n");
5151
5152     memset(&col, 0, sizeof(col));
5153     col.mask = LVCF_WIDTH | LVCF_TEXT;
5154     col.cx = 100;
5155     col.pszText = textA;
5156     ret = SendMessage(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5157     expect(0, ret);
5158
5159     header = ListView_GetHeader(list);
5160     ok(header != 0, "No header\n");
5161     memset(&itemW, 0, sizeof(itemW));
5162     itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5163     itemW.pszText = buffer;
5164     itemW.cchTextMax = sizeof(buffer);
5165     ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5166     expect(1, ret);
5167
5168     nmhdr.hdr.hwndFrom = header;
5169     nmhdr.hdr.idFrom = GetWindowLongPtr(header, GWLP_ID);
5170     nmhdr.iItem = 0;
5171     nmhdr.iButton = 0;
5172     nmhdr.pitem = &itemW;
5173
5174     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5175     nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5176     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5177     parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5178     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5179                 "header notify, parent", TRUE);
5180     todo_wine
5181     ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5182     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5183     nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5184     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5185     parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5186     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5187                 "header notify, parent", TRUE);
5188     todo_wine
5189     ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5190     /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5191     SetFocus(list);
5192     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5193     nmhdr.hdr.code = HDN_ITEMCLICKW;
5194     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5195     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5196                 "header notify, parent", FALSE);
5197     ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5198     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5199     nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5200     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5201     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5202                 "header notify, parent", FALSE);
5203     ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5204     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5205     nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5206     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5207     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5208                 "header notify, parent", TRUE);
5209     ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5210     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5211     nmhdr.hdr.code = HDN_BEGINTRACKW;
5212     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5213     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5214                 "header notify, parent", FALSE);
5215     ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5216     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5217     nmhdr.hdr.code = HDN_ENDTRACKW;
5218     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5219     parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5220     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5221                 "header notify, parent", FALSE);
5222     ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5223     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5224     nmhdr.hdr.code = HDN_TRACKW;
5225     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5226     parent_header_notify_seq[0].id = HDN_TRACKA;
5227     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5228                 "header notify, parent", FALSE);
5229     ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5230     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5231     nmhdr.hdr.code = HDN_BEGINDRAG;
5232     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5233     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5234                 "header notify, parent", FALSE);
5235     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5236     nmhdr.hdr.code = HDN_ENDDRAG;
5237     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5238     parent_header_notify_seq[0].id = HDN_ENDDRAG;
5239     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5240                 "header notify, parent", FALSE);
5241     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5242     nmhdr.hdr.code = HDN_FILTERCHANGE;
5243     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5244     parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5245     parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5246     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5247                 "header notify, parent", FALSE);
5248     parent_header_notify_seq[0].flags &= ~optional;
5249     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5250     nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5251     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5252     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5253                 "header notify, parent", FALSE);
5254     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5255     nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5256     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5257     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5258                 "header notify, parent", FALSE);
5259     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5260     nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5261     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5262     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5263                 "header notify, parent", FALSE);
5264     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5265     nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5266     ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5267     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5268                 "header notify, parent", FALSE);
5269
5270     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5271
5272     DestroyWindow(list);
5273 }
5274
5275 static void test_createdragimage(void)
5276 {
5277     HIMAGELIST himl;
5278     POINT pt;
5279     HWND list;
5280
5281     list = create_listview_control(LVS_ICON);
5282     ok(list != NULL, "failed to create listview window\n");
5283
5284     insert_item(list, 0);
5285
5286     /* NULL point */
5287     himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5288     ok(himl == NULL, "got %p\n", himl);
5289
5290     himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5291     ok(himl != NULL, "got %p\n", himl);
5292     ImageList_Destroy(himl);
5293
5294     DestroyWindow(list);
5295 }
5296
5297 static void test_dispinfo(void)
5298 {
5299     static const char testA[] = "TEST";
5300     WCHAR buff[10];
5301     LVITEMA item;
5302     HWND hwnd;
5303     DWORD ret;
5304
5305     hwnd = create_listview_control(LVS_ICON);
5306     ok(hwnd != NULL, "failed to create listview window\n");
5307
5308     insert_item(hwnd, 0);
5309
5310     memset(&item, 0, sizeof(item));
5311     item.pszText = LPSTR_TEXTCALLBACKA;
5312     ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5313     expect(1, ret);
5314
5315     g_disp_A_to_W = TRUE;
5316     item.pszText = (char*)buff;
5317     item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
5318     ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5319     ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
5320     g_disp_A_to_W = FALSE;
5321
5322     ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5323         "got %s, expected %s\n", item.pszText, testA);
5324
5325     DestroyWindow(hwnd);
5326 }
5327
5328 static void test_LVM_SETITEMTEXT(void)
5329 {
5330     static char testA[] = "TEST";
5331     LVITEMA item;
5332     HWND hwnd;
5333     DWORD ret;
5334
5335     hwnd = create_listview_control(LVS_ICON);
5336     ok(hwnd != NULL, "failed to create listview window\n");
5337
5338     insert_item(hwnd, 0);
5339
5340     /* null item pointer */
5341     ret = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, 0);
5342     expect(FALSE, ret);
5343
5344     ret = SendMessage(hwnd, LVM_SETITEMTEXTW, 0, 0);
5345     expect(FALSE, ret);
5346
5347     /* index out of bounds */
5348     item.pszText = testA;
5349     item.cchTextMax = 0; /* ignored */
5350     item.iSubItem = 0;
5351
5352     ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5353     expect(FALSE, ret);
5354
5355     ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5356     expect(FALSE, ret);
5357
5358     ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5359     expect(TRUE, ret);
5360
5361     DestroyWindow(hwnd);
5362 }
5363
5364 static void test_imagelists(void)
5365 {
5366     HWND hwnd, header;
5367     HIMAGELIST himl1, himl2, himl3;
5368     LRESULT ret;
5369
5370     himl1 = ImageList_Create(40, 40, 0, 4, 4);
5371     himl2 = ImageList_Create(40, 40, 0, 4, 4);
5372     himl3 = ImageList_Create(40, 40, 0, 4, 4);
5373     ok(himl1 != NULL, "Failed to create imagelist\n");
5374     ok(himl2 != NULL, "Failed to create imagelist\n");
5375     ok(himl3 != NULL, "Failed to create imagelist\n");
5376
5377     hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5378     header = subclass_header(hwnd);
5379
5380     ok(header != NULL, "Expected header\n");
5381     ret = SendMessage(header, HDM_GETIMAGELIST, 0, 0);
5382     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5383
5384     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5385
5386     ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5387     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5388     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5389                 "set normal image list", FALSE);
5390
5391     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5392
5393     ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5394     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5395     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5396                 "set state image list", TRUE);
5397
5398     ret = SendMessage(header, HDM_GETIMAGELIST, 0, 0);
5399     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5400
5401     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5402
5403     ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5404     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5405     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
5406                 "set small image list", FALSE);
5407
5408     ret = SendMessage(header, HDM_GETIMAGELIST, 0, 0);
5409     ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5410     DestroyWindow(hwnd);
5411
5412     hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
5413
5414     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5415
5416     ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
5417     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5418     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5419                 "set normal image list", FALSE);
5420
5421     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5422
5423     ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
5424     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5425     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5426                 "set state image list", FALSE);
5427
5428     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5429
5430     ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
5431     ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
5432     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
5433                 "set small image list", FALSE);
5434
5435     header = ListView_GetHeader(hwnd);
5436     ok(header == NULL, "Expected no header, got %p\n", header);
5437
5438     SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | LVS_REPORT);
5439
5440     header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
5441     ok(header != NULL, "Expected header, got NULL\n");
5442
5443     ret = SendMessage(header, HDM_GETIMAGELIST, 0, 0);
5444     ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
5445
5446     DestroyWindow(hwnd);
5447 }
5448
5449 static void test_deleteitem(void)
5450 {
5451     LVITEMA item;
5452     UINT state;
5453     HWND hwnd;
5454     BOOL ret;
5455
5456     hwnd = create_listview_control(LVS_REPORT);
5457
5458     insert_item(hwnd, 0);
5459     insert_item(hwnd, 0);
5460     insert_item(hwnd, 0);
5461     insert_item(hwnd, 0);
5462     insert_item(hwnd, 0);
5463
5464     g_focus_test_LVN_DELETEITEM = TRUE;
5465
5466     /* delete focused item (not the last index) */
5467     item.stateMask = LVIS_FOCUSED;
5468     item.state = LVIS_FOCUSED;
5469     ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
5470     ok(ret == TRUE, "got %d\n", ret);
5471     ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
5472     ok(ret == TRUE, "got %d\n", ret);
5473     /* next item gets focus */
5474     state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5475     ok(state == LVIS_FOCUSED, "got %x\n", state);
5476
5477     /* focus last item and delete it */
5478     item.stateMask = LVIS_FOCUSED;
5479     item.state = LVIS_FOCUSED;
5480     ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
5481     ok(ret == TRUE, "got %d\n", ret);
5482     ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
5483     ok(ret == TRUE, "got %d\n", ret);
5484     /* new last item gets focus */
5485     state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
5486     ok(state == LVIS_FOCUSED, "got %x\n", state);
5487
5488     /* focus first item and delete it */
5489     item.stateMask = LVIS_FOCUSED;
5490     item.state = LVIS_FOCUSED;
5491     ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
5492     ok(ret == TRUE, "got %d\n", ret);
5493     ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
5494     ok(ret == TRUE, "got %d\n", ret);
5495     /* new first item gets focus */
5496     state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5497     ok(state == LVIS_FOCUSED, "got %x\n", state);
5498
5499     g_focus_test_LVN_DELETEITEM = FALSE;
5500
5501     DestroyWindow(hwnd);
5502 }
5503
5504 static void test_insertitem(void)
5505 {
5506     LVITEMA item;
5507     UINT state;
5508     HWND hwnd;
5509     INT ret;
5510
5511     hwnd = create_listview_control(LVS_REPORT);
5512
5513     /* insert item 0 focused */
5514     item.mask = LVIF_STATE;
5515     item.state = LVIS_FOCUSED;
5516     item.stateMask = LVIS_FOCUSED;
5517     item.iItem = 0;
5518     item.iSubItem = 0;
5519     ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5520     ok(ret == 0, "got %d\n", ret);
5521
5522     state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
5523     ok(state == LVIS_FOCUSED, "got %x\n", state);
5524
5525     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5526
5527     /* insert item 1, focus shift */
5528     item.mask = LVIF_STATE;
5529     item.state = LVIS_FOCUSED;
5530     item.stateMask = LVIS_FOCUSED;
5531     item.iItem = 1;
5532     item.iSubItem = 0;
5533     ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5534     ok(ret == 1, "got %d\n", ret);
5535
5536     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused_seq, "insert focused", TRUE);
5537
5538     state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5539     ok(state == LVIS_FOCUSED, "got %x\n", state);
5540
5541     /* insert item 2, no focus shift */
5542     item.mask = LVIF_STATE;
5543     item.state = 0;
5544     item.stateMask = LVIS_FOCUSED;
5545     item.iItem = 2;
5546     item.iSubItem = 0;
5547     ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
5548     ok(ret == 2, "got %d\n", ret);
5549
5550     state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
5551     ok(state == LVIS_FOCUSED, "got %x\n", state);
5552
5553     DestroyWindow(hwnd);
5554 }
5555
5556 START_TEST(listview)
5557 {
5558     HMODULE hComctl32;
5559     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
5560
5561     ULONG_PTR ctx_cookie;
5562     HANDLE hCtx;
5563     HWND hwnd;
5564
5565     hComctl32 = GetModuleHandleA("comctl32.dll");
5566     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
5567     if (pInitCommonControlsEx)
5568     {
5569         INITCOMMONCONTROLSEX iccex;
5570         iccex.dwSize = sizeof(iccex);
5571         iccex.dwICC  = ICC_LISTVIEW_CLASSES;
5572         pInitCommonControlsEx(&iccex);
5573     }
5574     else
5575         InitCommonControls();
5576
5577     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
5578
5579     hwndparent = create_parent_window(FALSE);
5580     flush_sequences(sequences, NUM_MSG_SEQUENCES);
5581
5582     g_is_below_5 = is_below_comctl_5();
5583
5584     test_header_notification();
5585     test_header_notification2();
5586     test_images();
5587     test_checkboxes();
5588     test_items();
5589     test_create();
5590     test_redraw();
5591     test_customdraw();
5592     test_icon_spacing();
5593     test_color();
5594     test_item_count();
5595     test_item_position();
5596     test_columns();
5597     test_getorigin();
5598     test_multiselect();
5599     test_getitemrect();
5600     test_subitem_rect();
5601     test_sorting();
5602     test_ownerdata();
5603     test_norecompute();
5604     test_nosortheader();
5605     test_setredraw();
5606     test_hittest();
5607     test_getviewrect();
5608     test_getitemposition();
5609     test_columnscreation();
5610     test_editbox();
5611     test_notifyformat();
5612     test_indentation();
5613     test_getitemspacing();
5614     test_getcolumnwidth();
5615     test_approximate_viewrect();
5616     test_finditem();
5617     test_hover();
5618     test_destroynotify();
5619     test_createdragimage();
5620     test_dispinfo();
5621     test_LVM_SETITEMTEXT();
5622     test_imagelists();
5623     test_deleteitem();
5624     test_insertitem();
5625
5626     if (!load_v6_module(&ctx_cookie, &hCtx))
5627     {
5628         DestroyWindow(hwndparent);
5629         return;
5630     }
5631
5632     /* this is a XP SP3 failure workaround */
5633     hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
5634                            WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
5635                            0, 0, 100, 100,
5636                            hwndparent, NULL, GetModuleHandleA(NULL), NULL);
5637     if (!IsWindow(hwnd))
5638     {
5639         win_skip("FIXME: failed to create ListView window.\n");
5640         unload_v6_module(ctx_cookie, hCtx);
5641         DestroyWindow(hwndparent);
5642         return;
5643     }
5644     else
5645         DestroyWindow(hwnd);
5646
5647     /* comctl32 version 6 tests start here */
5648     test_get_set_view();
5649     test_canceleditlabel();
5650     test_mapidindex();
5651     test_scrollnotify();
5652     test_LVS_EX_TRANSPARENTBKGND();
5653     test_LVS_EX_HEADERINALLVIEWS();
5654     test_deleteitem();
5655     test_multiselect();
5656     test_insertitem();
5657
5658     unload_v6_module(ctx_cookie, hCtx);
5659
5660     DestroyWindow(hwndparent);
5661 }