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