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