comctl32: Fix a typo.
[wine] / dlls / comctl32 / tests / listview.c
1 /*
2  * ListView tests
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  * Copyright 2007 George Gov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdio.h>
23 #include <windows.h>
24 #include <commctrl.h>
25
26 #include "wine/test.h"
27 #include "msg.h"
28
29 #define PARENT_SEQ_INDEX    0
30 #define LISTVIEW_SEQ_INDEX  1
31 #define NUM_MSG_SEQUENCES   2
32
33 #define LISTVIEW_ID 0
34 #define HEADER_ID   1
35
36 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
37 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
38        "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
39
40 HWND hwndparent;
41
42 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
43
44 static const struct message create_parent_wnd_seq[] = {
45     { WM_GETMINMAXINFO,     sent },
46     { WM_NCCREATE,          sent },
47     { WM_NCCALCSIZE,        sent|wparam, 0 },
48     { WM_CREATE,            sent },
49     { WM_SHOWWINDOW,        sent|wparam, 1 },
50     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
51     { WM_QUERYNEWPALETTE,   sent|optional },
52     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
53     { WM_WINDOWPOSCHANGED,  sent|optional },
54     { WM_NCCALCSIZE,        sent|wparam|optional, 1 },
55     { WM_ACTIVATEAPP,       sent|wparam, 1 },
56     { WM_NCACTIVATE,        sent|wparam, 1 },
57     { WM_ACTIVATE,          sent|wparam, 1 },
58     { WM_IME_SETCONTEXT,    sent|wparam|defwinproc|optional, 1 },
59     { WM_IME_NOTIFY,        sent|defwinproc|optional },
60     { WM_SETFOCUS,          sent|wparam|defwinproc, 0 },
61     /* Win9x adds SWP_NOZORDER below */
62     { WM_WINDOWPOSCHANGED,  sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
63     { WM_NCCALCSIZE,        sent|wparam|optional, 1 },
64     { WM_SIZE,              sent },
65     { WM_MOVE,              sent },
66     { 0 }
67 };
68
69 static const struct message redraw_listview_seq[] = {
70     { WM_PAINT,      sent|id,            0, 0, LISTVIEW_ID },
71     { WM_PAINT,      sent|id,            0, 0, HEADER_ID },
72     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, HEADER_ID },
73     { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, HEADER_ID },
74     { WM_NOTIFY,     sent|id|defwinproc, 0, 0, LISTVIEW_ID },
75     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, LISTVIEW_ID },
76     { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
77     { 0 }
78 };
79
80 static const struct message listview_icon_spacing_seq[] = {
81     { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(20, 30) },
82     { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(25, 35) },
83     { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(-1, -1) },
84     { 0 }
85 };
86
87 static const struct message listview_color_seq[] = {
88     { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(0,0,0) },
89     { LVM_GETBKCOLOR,     sent },
90     { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(0,0,0) },
91     { LVM_GETTEXTCOLOR,   sent },
92     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
93     { LVM_GETTEXTBKCOLOR, sent },
94
95     { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(100,50,200) },
96     { LVM_GETBKCOLOR,     sent },
97     { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(100,50,200) },
98     { LVM_GETTEXTCOLOR,   sent },
99     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
100     { LVM_GETTEXTBKCOLOR, sent },
101
102     { LVM_SETBKCOLOR,     sent|lparam, 0, CLR_NONE },
103     { LVM_GETBKCOLOR,     sent },
104     { LVM_SETTEXTCOLOR,   sent|lparam, 0, CLR_NONE },
105     { LVM_GETTEXTCOLOR,   sent },
106     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
107     { LVM_GETTEXTBKCOLOR, sent },
108
109     { LVM_SETBKCOLOR,     sent|lparam, 0, RGB(255,255,255) },
110     { LVM_GETBKCOLOR,     sent },
111     { LVM_SETTEXTCOLOR,   sent|lparam, 0, RGB(255,255,255) },
112     { LVM_GETTEXTCOLOR,   sent },
113     { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
114     { LVM_GETTEXTBKCOLOR, sent },
115     { 0 }
116 };
117
118 static const struct message listview_item_count_seq[] = {
119     { LVM_GETITEMCOUNT,   sent },
120     { LVM_INSERTITEM,     sent },
121     { LVM_INSERTITEM,     sent },
122     { LVM_INSERTITEM,     sent },
123     { LVM_GETITEMCOUNT,   sent },
124     { LVM_DELETEITEM,     sent|wparam, 2 },
125     { LVM_GETITEMCOUNT,   sent },
126     { LVM_DELETEALLITEMS, sent },
127     { LVM_GETITEMCOUNT,   sent },
128     { LVM_INSERTITEM,     sent },
129     { LVM_INSERTITEM,     sent },
130     { LVM_GETITEMCOUNT,   sent },
131     { LVM_INSERTITEM,     sent },
132     { LVM_GETITEMCOUNT,   sent },
133     { 0 }
134 };
135
136 static const struct message listview_itempos_seq[] = {
137     { LVM_INSERTITEM,      sent },
138     { LVM_INSERTITEM,      sent },
139     { LVM_INSERTITEM,      sent },
140     { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
141     { LVM_GETITEMPOSITION, sent|wparam,        1 },
142     { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
143     { LVM_GETITEMPOSITION, sent|wparam,        2 },
144     { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
145     { LVM_GETITEMPOSITION, sent|wparam,        0 },
146     { 0 }
147 };
148
149 struct subclass_info
150 {
151     WNDPROC oldproc;
152 };
153
154 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
155 {
156     static long defwndproc_counter = 0;
157     LRESULT ret;
158     struct message msg;
159
160     /* do not log painting messages */
161     if (message != WM_PAINT &&
162         message != WM_ERASEBKGND &&
163         message != WM_NCPAINT &&
164         message != WM_NCHITTEST &&
165         message != WM_GETTEXT &&
166         message != WM_GETICON &&
167         message != WM_DEVICECHANGE)
168     {
169         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
170
171         msg.message = message;
172         msg.flags = sent|wparam|lparam;
173         if (defwndproc_counter) msg.flags |= defwinproc;
174         msg.wParam = wParam;
175         msg.lParam = lParam;
176         add_message(sequences, PARENT_SEQ_INDEX, &msg);
177     }
178
179     defwndproc_counter++;
180     ret = DefWindowProcA(hwnd, message, wParam, lParam);
181     defwndproc_counter--;
182
183     return ret;
184 }
185
186 static BOOL register_parent_wnd_class(void)
187 {
188     WNDCLASSA cls;
189
190     cls.style = 0;
191     cls.lpfnWndProc = parent_wnd_proc;
192     cls.cbClsExtra = 0;
193     cls.cbWndExtra = 0;
194     cls.hInstance = GetModuleHandleA(NULL);
195     cls.hIcon = 0;
196     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
197     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
198     cls.lpszMenuName = NULL;
199     cls.lpszClassName = "Listview test parent class";
200     return RegisterClassA(&cls);
201 }
202
203 static HWND create_parent_window(void)
204 {
205     if (!register_parent_wnd_class())
206         return NULL;
207
208     return CreateWindowEx(0, "Listview test parent class",
209                           "Listview test parent window",
210                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
211                           WS_MAXIMIZEBOX | WS_VISIBLE,
212                           0, 0, 100, 100,
213                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
214 }
215
216 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
217 {
218     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
219     static long defwndproc_counter = 0;
220     LRESULT ret;
221     struct message msg;
222
223     trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
224
225     msg.message = message;
226     msg.flags = sent|wparam|lparam;
227     if (defwndproc_counter) msg.flags |= defwinproc;
228     msg.wParam = wParam;
229     msg.lParam = lParam;
230     msg.id = LISTVIEW_ID;
231     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
232
233     defwndproc_counter++;
234     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
235     defwndproc_counter--;
236     return ret;
237 }
238
239 static HWND create_listview_control(void)
240 {
241     struct subclass_info *info;
242     HWND hwnd;
243     RECT rect;
244
245     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
246     if (!info)
247         return NULL;
248
249     GetClientRect(hwndparent, &rect);
250     hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
251                            WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
252                            0, 0, rect.right, rect.bottom,
253                            hwndparent, NULL, GetModuleHandleA(NULL), NULL);
254     ok(hwnd != NULL, "gle=%d\n", GetLastError());
255
256     if (!hwnd)
257     {
258         HeapFree(GetProcessHeap(), 0, info);
259         return NULL;
260     }
261
262     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
263                                             (LONG_PTR)listview_subclass_proc);
264     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
265
266     return hwnd;
267 }
268
269 static HWND create_custom_listview_control(DWORD style)
270 {
271     struct subclass_info *info;
272     HWND hwnd;
273     RECT rect;
274
275     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
276     if (!info)
277         return NULL;
278
279     GetClientRect(hwndparent, &rect);
280     hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
281                            WS_CHILD | WS_BORDER | WS_VISIBLE | style,
282                            0, 0, rect.right, rect.bottom,
283                            hwndparent, NULL, GetModuleHandleA(NULL), NULL);
284     ok(hwnd != NULL, "gle=%d\n", GetLastError());
285
286     if (!hwnd)
287     {
288         HeapFree(GetProcessHeap(), 0, info);
289         return NULL;
290     }
291
292     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
293                                             (LONG_PTR)listview_subclass_proc);
294     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
295
296     return hwnd;
297 }
298
299 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
300 {
301     struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
302     static long defwndproc_counter = 0;
303     LRESULT ret;
304     struct message msg;
305
306     trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
307
308     msg.message = message;
309     msg.flags = sent|wparam|lparam;
310     if (defwndproc_counter) msg.flags |= defwinproc;
311     msg.wParam = wParam;
312     msg.lParam = lParam;
313     msg.id = HEADER_ID;
314     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
315
316     defwndproc_counter++;
317     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
318     defwndproc_counter--;
319     return ret;
320 }
321
322 static HWND subclass_header(HWND hwndListview)
323 {
324     struct subclass_info *info;
325     HWND hwnd;
326
327     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
328     if (!info)
329         return NULL;
330
331     hwnd = ListView_GetHeader(hwndListview);
332     info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
333                                             (LONG_PTR)header_subclass_proc);
334     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
335
336     return hwnd;
337 }
338
339 static void test_images(void)
340 {
341     HWND hwnd;
342     DWORD r;
343     LVITEM item;
344     HIMAGELIST himl;
345     HBITMAP hbmp;
346     RECT r1, r2;
347     static CHAR hello[] = "hello";
348
349     himl = ImageList_Create(40, 40, 0, 4, 4);
350     ok(himl != NULL, "failed to create imagelist\n");
351
352     hbmp = CreateBitmap(40, 40, 1, 1, NULL);
353     ok(hbmp != NULL, "failed to create bitmap\n");
354
355     r = ImageList_Add(himl, hbmp, 0);
356     ok(r == 0, "should be zero\n");
357
358     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 
359                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
360     ok(hwnd != NULL, "failed to create listview window\n");
361
362     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
363     ok(r == 0, "should return zero\n");
364
365     r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
366     ok(r == 0, "should return zero\n");
367
368     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
369     /* returns dimensions */
370
371     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
372     ok(r == 0, "should be zero items\n");
373
374     item.mask = LVIF_IMAGE | LVIF_TEXT;
375     item.iItem = 0;
376     item.iSubItem = 1;
377     item.iImage = 0;
378     item.pszText = 0;
379     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
380     ok(r == -1, "should fail\n");
381
382     item.iSubItem = 0;
383     item.pszText = hello;
384     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
385     ok(r == 0, "should not fail\n");
386
387     memset(&r1, 0, sizeof r1);
388     r1.left = LVIR_ICON;
389     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
390
391     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
392     ok(r == TRUE, "should not fail\n");
393
394     item.iSubItem = 0;
395     item.pszText = hello;
396     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
397     ok(r == 0, "should not fail\n");
398
399     memset(&r2, 0, sizeof r2);
400     r2.left = LVIR_ICON;
401     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
402
403     ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
404
405     DestroyWindow(hwnd);
406 }
407
408 static void test_checkboxes(void)
409 {
410     HWND hwnd;
411     LVITEMA item;
412     DWORD r;
413     static CHAR text[]  = "Text",
414                 text2[] = "Text2",
415                 text3[] = "Text3";
416
417     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 
418                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
419     ok(hwnd != NULL, "failed to create listview window\n");
420
421     /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
422     item.mask = LVIF_TEXT | LVIF_STATE;
423     item.stateMask = 0xffff;
424     item.state = 0xfccc;
425     item.iItem = 0;
426     item.iSubItem = 0;
427     item.pszText = text;
428     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
429     ok(r == 0, "ret %d\n", r);
430
431     item.iItem = 0;
432     item.mask = LVIF_STATE;
433     item.stateMask = 0xffff;
434     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
435     ok(item.state == 0xfccc, "state %x\n", item.state);
436
437     /* Don't set LVIF_STATE */
438     item.mask = LVIF_TEXT;
439     item.stateMask = 0xffff;
440     item.state = 0xfccc;
441     item.iItem = 1;
442     item.iSubItem = 0;
443     item.pszText = text;
444     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
445     ok(r == 1, "ret %d\n", r);
446
447     item.iItem = 1;
448     item.mask = LVIF_STATE;
449     item.stateMask = 0xffff;
450     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
451     ok(item.state == 0, "state %x\n", item.state);
452
453     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
454     ok(r == 0, "should return zero\n");
455
456     /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
457     item.iItem = 0;
458     item.mask = LVIF_STATE;
459     item.stateMask = 0xffff;
460     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
461     ok(item.state == 0x1ccc, "state %x\n", item.state);
462
463     /* Now add an item without specifying a state and check that its state goes to 0x1000 */
464     item.iItem = 2;
465     item.mask = LVIF_TEXT;
466     item.state = 0;
467     item.pszText = text2;
468     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
469     ok(r == 2, "ret %d\n", r);
470
471     item.iItem = 2;
472     item.mask = LVIF_STATE;
473     item.stateMask = 0xffff;
474     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
475     ok(item.state == 0x1000, "state %x\n", item.state);
476
477     /* Add a further item this time specifying a state and still its state goes to 0x1000 */
478     item.iItem = 3;
479     item.mask = LVIF_TEXT | LVIF_STATE;
480     item.stateMask = 0xffff;
481     item.state = 0x2aaa;
482     item.pszText = text3;
483     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
484     ok(r == 3, "ret %d\n", r);
485
486     item.iItem = 3;
487     item.mask = LVIF_STATE;
488     item.stateMask = 0xffff;
489     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
490     ok(item.state == 0x1aaa, "state %x\n", item.state);
491
492     /* Set an item's state to checked */
493     item.iItem = 3;
494     item.mask = LVIF_STATE;
495     item.stateMask = 0xf000;
496     item.state = 0x2000;
497     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
498
499     item.iItem = 3;
500     item.mask = LVIF_STATE;
501     item.stateMask = 0xffff;
502     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
503     ok(item.state == 0x2aaa, "state %x\n", item.state);
504
505     /* Check that only the bits we asked for are returned,
506      * and that all the others are set to zero
507      */
508     item.iItem = 3;
509     item.mask = LVIF_STATE;
510     item.stateMask = 0xf000;
511     item.state = 0xffff;
512     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
513     ok(item.state == 0x2000, "state %x\n", item.state);
514
515     /* Set the style again and check that doesn't change an item's state */
516     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
517     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
518
519     item.iItem = 3;
520     item.mask = LVIF_STATE;
521     item.stateMask = 0xffff;
522     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
523     ok(item.state == 0x2aaa, "state %x\n", item.state);
524
525     /* Unsetting the checkbox extended style doesn't change an item's state */
526     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
527     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
528
529     item.iItem = 3;
530     item.mask = LVIF_STATE;
531     item.stateMask = 0xffff;
532     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
533     ok(item.state == 0x2aaa, "state %x\n", item.state);
534
535     /* Now setting the style again will change an item's state */
536     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
537     ok(r == 0, "ret %x\n", r);
538
539     item.iItem = 3;
540     item.mask = LVIF_STATE;
541     item.stateMask = 0xffff;
542     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
543     ok(item.state == 0x1aaa, "state %x\n", item.state);
544
545     /* Toggle checkbox tests (bug 9934) */
546     memset (&item, 0xcc, sizeof(item));
547     item.mask = LVIF_STATE;
548     item.iItem = 3;
549     item.iSubItem = 0;
550     item.state = LVIS_FOCUSED;
551     item.stateMask = LVIS_FOCUSED;
552     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
553     expect(1, r);
554
555     item.iItem = 3;
556     item.mask = LVIF_STATE;
557     item.stateMask = 0xffff;
558     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
559     ok(item.state == 0x1aab, "state %x\n", item.state);
560
561     r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
562     expect(0, r);
563     r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
564     expect(0, r);
565
566     item.iItem = 3;
567     item.mask = LVIF_STATE;
568     item.stateMask = 0xffff;
569     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
570     ok(item.state == 0x2aab, "state %x\n", item.state);
571
572     r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
573     expect(0, r);
574     r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
575     expect(0, r);
576
577     item.iItem = 3;
578     item.mask = LVIF_STATE;
579     item.stateMask = 0xffff;
580     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
581     ok(item.state == 0x1aab, "state %x\n", item.state);
582
583     DestroyWindow(hwnd);
584 }
585
586 static void insert_column(HWND hwnd, int idx)
587 {
588     LVCOLUMN column;
589     DWORD rc;
590
591     memset(&column, 0xcc, sizeof(column));
592     column.mask = LVCF_SUBITEM;
593     column.iSubItem = idx;
594
595     rc = ListView_InsertColumn(hwnd, idx, &column);
596     expect(idx, rc);
597 }
598
599 static void insert_item(HWND hwnd, int idx)
600 {
601     static CHAR text[] = "foo";
602
603     LVITEMA item;
604     DWORD rc;
605
606     memset(&item, 0xcc, sizeof (item));
607     item.mask = LVIF_TEXT;
608     item.iItem = idx;
609     item.iSubItem = 0;
610     item.pszText = text;
611
612     rc = ListView_InsertItem(hwnd, &item);
613     expect(idx, rc);
614 }
615
616 static void test_items(void)
617 {
618     const LPARAM lparamTest = 0x42;
619     HWND hwnd;
620     LVITEMA item;
621     DWORD r;
622     static CHAR text[] = "Text";
623
624     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
625                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
626     ok(hwnd != NULL, "failed to create listview window\n");
627
628     /*
629      * Test setting/getting item params
630      */
631
632     /* Set up two columns */
633     insert_column(hwnd, 0);
634     insert_column(hwnd, 1);
635
636     /* Insert an item with just a param */
637     memset (&item, 0xcc, sizeof (item));
638     item.mask = LVIF_PARAM;
639     item.iItem = 0;
640     item.iSubItem = 0;
641     item.lParam = lparamTest;
642     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
643     ok(r == 0, "ret %d\n", r);
644
645     /* Test getting of the param */
646     memset (&item, 0xcc, sizeof (item));
647     item.mask = LVIF_PARAM;
648     item.iItem = 0;
649     item.iSubItem = 0;
650     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
651     ok(r != 0, "ret %d\n", r);
652     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
653
654     /* Set up a subitem */
655     memset (&item, 0xcc, sizeof (item));
656     item.mask = LVIF_TEXT;
657     item.iItem = 0;
658     item.iSubItem = 1;
659     item.pszText = text;
660     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
661     ok(r != 0, "ret %d\n", r);
662
663     /* Query param from subitem: returns main item param */
664     memset (&item, 0xcc, sizeof (item));
665     item.mask = LVIF_PARAM;
666     item.iItem = 0;
667     item.iSubItem = 1;
668     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
669     ok(r != 0, "ret %d\n", r);
670     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
671
672     /* Set up param on first subitem: no effect */
673     memset (&item, 0xcc, sizeof (item));
674     item.mask = LVIF_PARAM;
675     item.iItem = 0;
676     item.iSubItem = 1;
677     item.lParam = lparamTest+1;
678     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
679     ok(r == 0, "ret %d\n", r);
680
681     /* Query param from subitem again: should still return main item param */
682     memset (&item, 0xcc, sizeof (item));
683     item.mask = LVIF_PARAM;
684     item.iItem = 0;
685     item.iSubItem = 1;
686     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
687     ok(r != 0, "ret %d\n", r);
688     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
689
690     /**** Some tests of state highlighting ****/
691     memset (&item, 0xcc, sizeof (item));
692     item.mask = LVIF_STATE;
693     item.iItem = 0;
694     item.iSubItem = 0;
695     item.state = LVIS_SELECTED;
696     item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
697     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
698     ok(r != 0, "ret %d\n", r);
699     item.iSubItem = 1;
700     item.state = LVIS_DROPHILITED;
701     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
702     ok(r != 0, "ret %d\n", r);
703
704     memset (&item, 0xcc, sizeof (item));
705     item.mask = LVIF_STATE;
706     item.iItem = 0;
707     item.iSubItem = 0;
708     item.stateMask = -1;
709     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
710     ok(r != 0, "ret %d\n", r);
711     ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
712     item.iSubItem = 1;
713     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
714     ok(r != 0, "ret %d\n", r);
715     todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
716
717     DestroyWindow(hwnd);
718 }
719
720 static void test_columns(void)
721 {
722     HWND hwnd;
723     LVCOLUMN column;
724     DWORD rc;
725
726     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
727                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
728     ok(hwnd != NULL, "failed to create listview window\n");
729
730     /* Add a column with no mask */
731     memset(&column, 0xcc, sizeof(column));
732     column.mask = 0;
733     rc = ListView_InsertColumn(hwnd, 0, &column);
734     ok(rc==0, "Inserting column with no mask failed with %d\n", rc);
735
736     /* Check its width */
737     rc = ListView_GetColumnWidth(hwnd, 0);
738     ok(rc==10 ||
739        broken(rc==0), /* win9x */
740        "Inserting column with no mask failed to set width to 10 with %d\n", rc);
741
742     DestroyWindow(hwnd);
743 }
744 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
745 static WNDPROC listviewWndProc;
746 static HIMAGELIST test_create_imagelist;
747
748 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
749 {
750     if (uMsg == WM_CREATE)
751     {
752         LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
753         lpcs->style |= LVS_REPORT;
754         SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
755     }
756     return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
757 }
758
759 static void test_create(void)
760 {
761     HWND hList;
762     HWND hHeader;
763     WNDCLASSEX cls;
764     cls.cbSize = sizeof(WNDCLASSEX);
765     ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
766     listviewWndProc = cls.lpfnWndProc;
767     cls.lpfnWndProc = create_test_wndproc;
768     cls.lpszClassName = "MyListView32";
769     ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
770
771     test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
772     hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
773     ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
774     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
775     ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
776     DestroyWindow(hList);
777 }
778
779 static void test_redraw(void)
780 {
781     HWND hwnd, hwndheader;
782
783     hwnd = create_listview_control();
784     hwndheader = subclass_header(hwnd);
785
786     flush_sequences(sequences, NUM_MSG_SEQUENCES);
787
788     trace("invalidate & update\n");
789     InvalidateRect(hwnd, NULL, TRUE);
790     UpdateWindow(hwnd);
791     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
792
793     flush_sequences(sequences, NUM_MSG_SEQUENCES);
794
795     DestroyWindow(hwnd);
796 }
797
798 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
799 {
800     COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
801
802     if(msg == WM_NOTIFY) {
803         NMHDR *nmhdr = (PVOID)lp;
804         if(nmhdr->code == NM_CUSTOMDRAW) {
805             NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
806             trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
807             switch(nmlvcd->nmcd.dwDrawStage) {
808             case CDDS_PREPAINT:
809                 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
810                 return CDRF_NOTIFYITEMDRAW;
811             case CDDS_ITEMPREPAINT:
812                 nmlvcd->clrTextBk = CLR_DEFAULT;
813                 return CDRF_NOTIFYSUBITEMDRAW;
814             case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
815                 clr = GetBkColor(nmlvcd->nmcd.hdc);
816                 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
817                 return CDRF_NOTIFYPOSTPAINT;
818             case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
819                 clr = GetBkColor(nmlvcd->nmcd.hdc);
820                 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
821                 return CDRF_DODEFAULT;
822             }
823             return CDRF_DODEFAULT;
824         }
825     }
826
827     return DefWindowProcA(hwnd, msg, wp, lp);
828 }
829
830 static void test_customdraw(void)
831 {
832     HWND hwnd;
833     WNDPROC oldwndproc;
834
835     hwnd = create_listview_control();
836
837     insert_column(hwnd, 0);
838     insert_column(hwnd, 1);
839     insert_item(hwnd, 0);
840
841     oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
842                                            (LONG_PTR)cd_wndproc);
843
844     InvalidateRect(hwnd, NULL, TRUE);
845     UpdateWindow(hwnd);
846
847     SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
848
849     DestroyWindow(hwnd);
850 }
851
852 static void test_icon_spacing(void)
853 {
854     /* LVM_SETICONSPACING */
855     /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
856
857     HWND hwnd;
858     WORD w, h;
859     DWORD r;
860
861     hwnd = create_custom_listview_control(LVS_ICON);
862     ok(hwnd != NULL, "failed to create a listview window\n");
863
864     r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY);
865     expect(NFR_ANSI, r);
866
867     /* reset the icon spacing to defaults */
868     SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1, -1));
869
870     /* now we can request what the defaults are */
871     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1, -1));
872     w = LOWORD(r);
873     h = HIWORD(r);
874
875     flush_sequences(sequences, NUM_MSG_SEQUENCES);
876
877     trace("test icon spacing\n");
878
879     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(20, 30));
880     ok(r == MAKELONG(w, h) ||
881        broken(r == MAKELONG(w, w)), /* win98 */
882        "Expected %d, got %d\n", MAKELONG(w, h), r);
883
884     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(25, 35));
885     expect(MAKELONG(20,30), r);
886
887     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1,-1));
888     expect(MAKELONG(25,35), r);
889
890     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
891
892     flush_sequences(sequences, NUM_MSG_SEQUENCES);
893     DestroyWindow(hwnd);
894 }
895
896 static void test_color(void)
897 {
898     /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
899
900     HWND hwnd;
901     DWORD r;
902     int i;
903
904     COLORREF color;
905     COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
906
907     hwnd = create_listview_control();
908     ok(hwnd != NULL, "failed to create a listview window\n");
909
910     flush_sequences(sequences, NUM_MSG_SEQUENCES);
911
912     trace("test color seq\n");
913     for (i = 0; i < 4; i++)
914     {
915         color = colors[i];
916
917         r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
918         expect(TRUE, r);
919         r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color);
920         expect(color, r);
921
922         r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
923         expect (TRUE, r);
924         r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color);
925         expect(color, r);
926
927         r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
928         expect(TRUE, r);
929         r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color);
930         expect(color, r);
931     }
932
933     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
934
935     flush_sequences(sequences, NUM_MSG_SEQUENCES);
936     DestroyWindow(hwnd);
937 }
938
939 static void test_item_count(void)
940 {
941     /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
942
943     HWND hwnd;
944     DWORD r;
945
946     LVITEM item0;
947     LVITEM item1;
948     LVITEM item2;
949     static CHAR item0text[] = "item0";
950     static CHAR item1text[] = "item1";
951     static CHAR item2text[] = "item2";
952
953     hwnd = create_listview_control();
954     ok(hwnd != NULL, "failed to create a listview window\n");
955
956     flush_sequences(sequences, NUM_MSG_SEQUENCES);
957
958     trace("test item count\n");
959
960     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
961     expect(0, r);
962
963     /* [item0] */
964     item0.mask = LVIF_TEXT;
965     item0.iItem = 0;
966     item0.iSubItem = 0;
967     item0.pszText = item0text;
968     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
969     expect(0, r);
970
971     /* [item0, item1] */
972     item1.mask = LVIF_TEXT;
973     item1.iItem = 1;
974     item1.iSubItem = 0;
975     item1.pszText = item1text;
976     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
977     expect(1, r);
978
979     /* [item0, item1, item2] */
980     item2.mask = LVIF_TEXT;
981     item2.iItem = 2;
982     item2.iSubItem = 0;
983     item2.pszText = item2text;
984     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
985     expect(2, r);
986
987     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
988     expect(3, r);
989
990     /* [item0, item1] */
991     r = SendMessage(hwnd, LVM_DELETEITEM, (WPARAM) 2, 0);
992     expect(TRUE, r);
993
994     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
995     expect(2, r);
996
997     /* [] */
998     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
999     expect(TRUE, r);
1000
1001     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1002     expect(0, r);
1003
1004     /* [item0] */
1005     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1006     expect(0, r);
1007
1008     /* [item0, item1] */
1009     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1010     expect(1, r);
1011
1012     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1013     expect(2, r);
1014
1015     /* [item0, item1, item2] */
1016     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1017     expect(2, r);
1018
1019     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1020     expect(3, r);
1021
1022     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
1023
1024     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1025     DestroyWindow(hwnd);
1026 }
1027
1028 static void test_item_position(void)
1029 {
1030     /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1031
1032     HWND hwnd;
1033     DWORD r;
1034     POINT position;
1035
1036     LVITEM item0;
1037     LVITEM item1;
1038     LVITEM item2;
1039     static CHAR item0text[] = "item0";
1040     static CHAR item1text[] = "item1";
1041     static CHAR item2text[] = "item2";
1042
1043     hwnd = create_custom_listview_control(LVS_ICON);
1044     ok(hwnd != NULL, "failed to create a listview window\n");
1045
1046     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1047
1048     trace("test item position\n");
1049
1050     /* [item0] */
1051     item0.mask = LVIF_TEXT;
1052     item0.iItem = 0;
1053     item0.iSubItem = 0;
1054     item0.pszText = item0text;
1055     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1056     expect(0, r);
1057
1058     /* [item0, item1] */
1059     item1.mask = LVIF_TEXT;
1060     item1.iItem = 1;
1061     item1.iSubItem = 0;
1062     item1.pszText = item1text;
1063     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1064     expect(1, r);
1065
1066     /* [item0, item1, item2] */
1067     item2.mask = LVIF_TEXT;
1068     item2.iItem = 2;
1069     item2.iSubItem = 0;
1070     item2.pszText = item2text;
1071     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1072     expect(2, r);
1073
1074     r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
1075     expect(TRUE, r);
1076     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
1077     expect(TRUE, r);
1078     expect2(10, 5, position.x, position.y);
1079
1080     r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
1081     expect(TRUE, r);
1082     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
1083     expect(TRUE, r);
1084     expect2(0, 0, position.x, position.y);
1085
1086     r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
1087     expect(TRUE, r);
1088     r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
1089     expect(TRUE, r);
1090     expect2(20, 20, position.x, position.y);
1091
1092     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
1093
1094     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1095     DestroyWindow(hwnd);
1096 }
1097
1098 static void test_getorigin(void)
1099 {
1100     /* LVM_GETORIGIN */
1101
1102     HWND hwnd;
1103     DWORD r;
1104     POINT position;
1105
1106     position.x = position.y = 0;
1107
1108     hwnd = create_custom_listview_control(LVS_ICON);
1109     ok(hwnd != NULL, "failed to create a listview window\n");
1110     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1111     trace("test get origin results\n");
1112     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1113     expect(TRUE, r);
1114     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1115     DestroyWindow(hwnd);
1116
1117     hwnd = create_custom_listview_control(LVS_SMALLICON);
1118     ok(hwnd != NULL, "failed to create a listview window\n");
1119     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1120     trace("test get origin results\n");
1121     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1122     expect(TRUE, r);
1123     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1124     DestroyWindow(hwnd);
1125
1126     hwnd = create_custom_listview_control(LVS_LIST);
1127     ok(hwnd != NULL, "failed to create a listview window\n");
1128     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1129     trace("test get origin results\n");
1130     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1131     expect(FALSE, r);
1132     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1133     DestroyWindow(hwnd);
1134
1135     hwnd = create_custom_listview_control(LVS_REPORT);
1136     ok(hwnd != NULL, "failed to create a listview window\n");
1137     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1138     trace("test get origin results\n");
1139     r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1140     expect(FALSE, r);
1141     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1142     DestroyWindow(hwnd);
1143
1144 }
1145
1146 static void test_multiselect(void)
1147 {
1148     typedef struct t_select_task
1149     {
1150         const char *descr;
1151         int initPos;
1152         int loopVK;
1153         int count;
1154         int result;
1155     } select_task;
1156
1157     HWND hwnd;
1158     DWORD r;
1159     int i,j,item_count,selected_count;
1160     static const int items=5;
1161     BYTE kstate[256];
1162     select_task task;
1163
1164     static struct t_select_task task_list[] = {
1165         { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
1166         { "using VK_UP", -1, VK_UP, -1, -1 },
1167         { "using VK_END", 0, VK_END, 1, -1 },
1168         { "using VK_HOME", -1, VK_HOME, 1, -1 }
1169     };
1170
1171
1172     hwnd = create_listview_control();
1173
1174     for (i=0;i<items;i++) {
1175             insert_item(hwnd, 0);
1176     }
1177
1178     item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1179
1180     expect(items,item_count);
1181
1182     for (i=0;i<4;i++) {
1183         task = task_list[i];
1184
1185         /* deselect all items */
1186         ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1187         SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1188
1189         /* set initial position */
1190         SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
1191         ListView_SetItemState(hwnd,(task.initPos == -1 ? item_count -1 : task.initPos),LVIS_SELECTED ,LVIS_SELECTED);
1192
1193         selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1194
1195         ok(selected_count == 1, "There should be only one selected item at the beginning (is %d)\n",selected_count);
1196
1197         /* Set SHIFT key pressed */
1198         GetKeyboardState(kstate);
1199         kstate[VK_SHIFT]=0x80;
1200         SetKeyboardState(kstate);
1201
1202         for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
1203             r = SendMessage(hwnd, WM_KEYDOWN, task.loopVK, 0);
1204             expect(0,r);
1205             r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
1206             expect(0,r);
1207         }
1208
1209         selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1210
1211         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);
1212
1213         /* Set SHIFT key released */
1214         GetKeyboardState(kstate);
1215         kstate[VK_SHIFT]=0x00;
1216         SetKeyboardState(kstate);
1217     }
1218     DestroyWindow(hwnd);
1219 }
1220
1221 START_TEST(listview)
1222 {
1223     HMODULE hComctl32;
1224     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
1225
1226     hComctl32 = GetModuleHandleA("comctl32.dll");
1227     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
1228     if (pInitCommonControlsEx)
1229     {
1230         INITCOMMONCONTROLSEX iccex;
1231         iccex.dwSize = sizeof(iccex);
1232         iccex.dwICC  = ICC_LISTVIEW_CLASSES;
1233         pInitCommonControlsEx(&iccex);
1234     }
1235     else
1236         InitCommonControls();
1237
1238     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1239
1240     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1241     hwndparent = create_parent_window();
1242     ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent window", TRUE);
1243     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1244
1245     test_images();
1246     test_checkboxes();
1247     test_items();
1248     test_create();
1249     test_redraw();
1250     test_customdraw();
1251     test_icon_spacing();
1252     test_color();
1253     test_item_count();
1254     test_item_position();
1255     test_columns();
1256     test_getorigin();
1257     test_multiselect();
1258 }