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