qcap: Add DebugInfo to critical sections.
[wine] / dlls / comctl32 / tests / listview.c
1 /*
2  * ListView tests
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22 #include <windows.h>
23 #include <commctrl.h>
24
25 #include "wine/test.h"
26 #include "msg.h"
27
28 #define PARENT_SEQ_INDEX    0
29 #define LISTVIEW_SEQ_INDEX  1
30 #define NUM_MSG_SEQUENCES   2
31
32 #define LISTVIEW_ID 0
33 #define HEADER_ID   1
34
35 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
36
37 HWND hwndparent;
38
39 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
40
41 static const struct message redraw_listview_seq[] = {
42     { WM_PAINT,      sent|id,            0, 0, LISTVIEW_ID },
43     { WM_PAINT,      sent|id,            0, 0, HEADER_ID },
44     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, HEADER_ID },
45     { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, HEADER_ID },
46     { WM_NOTIFY,     sent|id|defwinproc, 0, 0, LISTVIEW_ID },
47     { WM_NCPAINT,    sent|id|defwinproc, 0, 0, LISTVIEW_ID },
48     { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
49     { 0 }
50 };
51
52 struct subclass_info
53 {
54     WNDPROC oldproc;
55 };
56
57 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
58 {
59     static long defwndproc_counter = 0;
60     LRESULT ret;
61     struct message msg;
62
63     /* do not log painting messages */
64     if (message != WM_PAINT &&
65         message != WM_ERASEBKGND &&
66         message != WM_NCPAINT &&
67         message != WM_NCHITTEST &&
68         message != WM_GETTEXT &&
69         message != WM_GETICON &&
70         message != WM_DEVICECHANGE)
71     {
72         trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
73
74         msg.message = message;
75         msg.flags = sent|wparam|lparam;
76         if (defwndproc_counter) msg.flags |= defwinproc;
77         msg.wParam = wParam;
78         msg.lParam = lParam;
79         add_message(sequences, PARENT_SEQ_INDEX, &msg);
80     }
81
82     defwndproc_counter++;
83     ret = DefWindowProcA(hwnd, message, wParam, lParam);
84     defwndproc_counter--;
85
86     return ret;
87 }
88
89 static BOOL register_parent_wnd_class(void)
90 {
91     WNDCLASSA cls;
92
93     cls.style = 0;
94     cls.lpfnWndProc = parent_wnd_proc;
95     cls.cbClsExtra = 0;
96     cls.cbWndExtra = 0;
97     cls.hInstance = GetModuleHandleA(NULL);
98     cls.hIcon = 0;
99     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
100     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
101     cls.lpszMenuName = NULL;
102     cls.lpszClassName = "Listview test parent class";
103     return RegisterClassA(&cls);
104 }
105
106 static HWND create_parent_window(void)
107 {
108     if (!register_parent_wnd_class())
109         return NULL;
110
111     return CreateWindowEx(0, "Listview test parent class",
112                           "Listview test parent window",
113                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
114                           WS_MAXIMIZEBOX | WS_VISIBLE,
115                           0, 0, 100, 100,
116                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
117 }
118
119 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
120 {
121     struct subclass_info *info = (struct subclass_info *)GetWindowLongA(hwnd, GWL_USERDATA);
122     static long defwndproc_counter = 0;
123     LRESULT ret;
124     struct message msg;
125
126     trace("listview: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
127
128     msg.message = message;
129     msg.flags = sent|wparam|lparam;
130     if (defwndproc_counter) msg.flags |= defwinproc;
131     msg.wParam = wParam;
132     msg.lParam = lParam;
133     msg.id = LISTVIEW_ID;
134     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
135
136     defwndproc_counter++;
137     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
138     defwndproc_counter--;
139     return ret;
140 }
141
142 static HWND create_listview_control(void)
143 {
144     struct subclass_info *info;
145     HWND hwnd;
146     RECT rect;
147
148     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
149     if (!info)
150         return NULL;
151
152     GetClientRect(hwndparent, &rect);
153     hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
154                            WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
155                            0, 0, rect.right, rect.bottom,
156                            hwndparent, NULL, GetModuleHandleA(NULL), NULL);
157     ok(hwnd != NULL, "gle=%d\n", GetLastError());
158
159     if (!hwnd)
160     {
161         HeapFree(GetProcessHeap(), 0, info);
162         return NULL;
163     }
164
165     info->oldproc = (WNDPROC)SetWindowLongA(hwnd, GWL_WNDPROC,
166                                             (LONG)listview_subclass_proc);
167     SetWindowLongA(hwnd, GWL_USERDATA, (LONG)info);
168
169     return hwnd;
170 }
171
172 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
173 {
174     struct subclass_info *info = (struct subclass_info *)GetWindowLongA(hwnd, GWL_USERDATA);
175     static long defwndproc_counter = 0;
176     LRESULT ret;
177     struct message msg;
178
179     trace("header: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
180
181     msg.message = message;
182     msg.flags = sent|wparam|lparam;
183     if (defwndproc_counter) msg.flags |= defwinproc;
184     msg.wParam = wParam;
185     msg.lParam = lParam;
186     msg.id = HEADER_ID;
187     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
188
189     defwndproc_counter++;
190     ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
191     defwndproc_counter--;
192     return ret;
193 }
194
195 static HWND subclass_header(HWND hwndListview)
196 {
197     struct subclass_info *info;
198     HWND hwnd;
199
200     info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
201     if (!info)
202         return NULL;
203
204     hwnd = ListView_GetHeader(hwndListview);
205     info->oldproc = (WNDPROC)SetWindowLongA(hwnd, GWL_WNDPROC,
206                                             (LONG)header_subclass_proc);
207     SetWindowLongA(hwnd, GWL_USERDATA, (LONG)info);
208
209     return hwnd;
210 }
211
212 static void test_images(void)
213 {
214     HWND hwnd;
215     DWORD r;
216     LVITEM item;
217     HIMAGELIST himl;
218     HBITMAP hbmp;
219     RECT r1, r2;
220     static CHAR hello[] = "hello";
221
222     himl = ImageList_Create(40, 40, 0, 4, 4);
223     ok(himl != NULL, "failed to create imagelist\n");
224
225     hbmp = CreateBitmap(40, 40, 1, 1, NULL);
226     ok(hbmp != NULL, "failed to create bitmap\n");
227
228     r = ImageList_Add(himl, hbmp, 0);
229     ok(r == 0, "should be zero\n");
230
231     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 
232                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
233     ok(hwnd != NULL, "failed to create listview window\n");
234
235     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
236     ok(r == 0, "should return zero\n");
237
238     r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
239     ok(r == 0, "should return zero\n");
240
241     r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
242     /* returns dimensions */
243
244     r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
245     ok(r == 0, "should be zero items\n");
246
247     item.mask = LVIF_IMAGE | LVIF_TEXT;
248     item.iItem = 0;
249     item.iSubItem = 1;
250     item.iImage = 0;
251     item.pszText = 0;
252     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
253     ok(r == -1, "should fail\n");
254
255     item.iSubItem = 0;
256     item.pszText = hello;
257     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
258     ok(r == 0, "should not fail\n");
259
260     memset(&r1, 0, sizeof r1);
261     r1.left = LVIR_ICON;
262     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
263
264     r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
265     ok(r == TRUE, "should not fail\n");
266
267     item.iSubItem = 0;
268     item.pszText = hello;
269     r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
270     ok(r == 0, "should not fail\n");
271
272     memset(&r2, 0, sizeof r2);
273     r2.left = LVIR_ICON;
274     r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
275
276     ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
277
278     DestroyWindow(hwnd);
279 }
280
281 static void test_checkboxes(void)
282 {
283     HWND hwnd;
284     LVITEMA item;
285     DWORD r;
286     static CHAR text[]  = "Text",
287                 text2[] = "Text2",
288                 text3[] = "Text3";
289
290     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 
291                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
292     ok(hwnd != NULL, "failed to create listview window\n");
293
294     /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
295     item.mask = LVIF_TEXT | LVIF_STATE;
296     item.stateMask = 0xffff;
297     item.state = 0xfccc;
298     item.iItem = 0;
299     item.iSubItem = 0;
300     item.pszText = text;
301     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
302     ok(r == 0, "ret %d\n", r);
303
304     item.iItem = 0;
305     item.mask = LVIF_STATE;
306     item.stateMask = 0xffff;
307     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
308     ok(item.state == 0xfccc, "state %x\n", item.state);
309
310     /* Don't set LVIF_STATE */
311     item.mask = LVIF_TEXT;
312     item.stateMask = 0xffff;
313     item.state = 0xfccc;
314     item.iItem = 1;
315     item.iSubItem = 0;
316     item.pszText = text;
317     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
318     ok(r == 1, "ret %d\n", r);
319
320     item.iItem = 1;
321     item.mask = LVIF_STATE;
322     item.stateMask = 0xffff;
323     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
324     ok(item.state == 0, "state %x\n", item.state);
325
326     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
327     ok(r == 0, "should return zero\n");
328
329     /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
330     item.iItem = 0;
331     item.mask = LVIF_STATE;
332     item.stateMask = 0xffff;
333     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
334     ok(item.state == 0x1ccc, "state %x\n", item.state);
335
336     /* Now add an item without specifying a state and check that its state goes to 0x1000 */
337     item.iItem = 2;
338     item.mask = LVIF_TEXT;
339     item.state = 0;
340     item.pszText = text2;
341     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
342     ok(r == 2, "ret %d\n", r);
343
344     item.iItem = 2;
345     item.mask = LVIF_STATE;
346     item.stateMask = 0xffff;
347     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
348     ok(item.state == 0x1000, "state %x\n", item.state);
349
350     /* Add a further item this time specifying a state and still its state goes to 0x1000 */
351     item.iItem = 3;
352     item.mask = LVIF_TEXT | LVIF_STATE;
353     item.stateMask = 0xffff;
354     item.state = 0x2aaa;
355     item.pszText = text3;
356     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
357     ok(r == 3, "ret %d\n", r);
358
359     item.iItem = 3;
360     item.mask = LVIF_STATE;
361     item.stateMask = 0xffff;
362     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
363     ok(item.state == 0x1aaa, "state %x\n", item.state);
364
365     /* Set an item's state to checked */
366     item.iItem = 3;
367     item.mask = LVIF_STATE;
368     item.stateMask = 0xf000;
369     item.state = 0x2000;
370     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
371
372     item.iItem = 3;
373     item.mask = LVIF_STATE;
374     item.stateMask = 0xffff;
375     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
376     ok(item.state == 0x2aaa, "state %x\n", item.state);
377
378     /* Check that only the bits we asked for are returned,
379      * and that all the others are set to zero
380      */
381     item.iItem = 3;
382     item.mask = LVIF_STATE;
383     item.stateMask = 0xf000;
384     item.state = 0xffff;
385     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
386     ok(item.state == 0x2000, "state %x\n", item.state);
387
388     /* Set the style again and check that doesn't change an item's state */
389     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
390     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
391
392     item.iItem = 3;
393     item.mask = LVIF_STATE;
394     item.stateMask = 0xffff;
395     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
396     ok(item.state == 0x2aaa, "state %x\n", item.state);
397
398     /* Unsetting the checkbox extended style doesn't change an item's state */
399     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
400     ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
401
402     item.iItem = 3;
403     item.mask = LVIF_STATE;
404     item.stateMask = 0xffff;
405     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
406     ok(item.state == 0x2aaa, "state %x\n", item.state);
407
408     /* Now setting the style again will change an item's state */
409     r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
410     ok(r == 0, "ret %x\n", r);
411
412     item.iItem = 3;
413     item.mask = LVIF_STATE;
414     item.stateMask = 0xffff;
415     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
416     ok(item.state == 0x1aaa, "state %x\n", item.state);
417
418     DestroyWindow(hwnd);
419 }
420
421 static void insert_column(HWND hwnd, int idx)
422 {
423     LVCOLUMN column;
424     DWORD rc;
425
426     memset(&column, 0xaa, sizeof(column));
427     column.mask = LVCF_SUBITEM;
428     column.iSubItem = idx;
429
430     rc = ListView_InsertColumn(hwnd, idx, &column);
431     expect(idx, rc);
432 }
433
434 static void insert_item(HWND hwnd, int idx)
435 {
436     static CHAR text[] = "foo";
437
438     LVITEMA item;
439     DWORD rc;
440
441     memset(&item, 0xaa, sizeof (item));
442     item.mask = LVIF_TEXT;
443     item.iItem = idx;
444     item.iSubItem = 0;
445     item.pszText = text;
446
447     rc = ListView_InsertItemA(hwnd, &item);
448     expect(idx, rc);
449 }
450
451 static void test_items(void)
452 {
453     const LPARAM lparamTest = 0x42;
454     HWND hwnd;
455     LVITEMA item;
456     DWORD r;
457     static CHAR text[] = "Text";
458
459     hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
460                 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
461     ok(hwnd != NULL, "failed to create listview window\n");
462
463     /*
464      * Test setting/getting item params
465      */
466
467     /* Set up two columns */
468     insert_column(hwnd, 0);
469     insert_column(hwnd, 1);
470
471     /* Insert an item with just a param */
472     memset (&item, 0xaa, sizeof (item));
473     item.mask = LVIF_PARAM;
474     item.iItem = 0;
475     item.iSubItem = 0;
476     item.lParam = lparamTest;
477     r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
478     ok(r == 0, "ret %d\n", r);
479
480     /* Test getting of the param */
481     memset (&item, 0xaa, sizeof (item));
482     item.mask = LVIF_PARAM;
483     item.iItem = 0;
484     item.iSubItem = 0;
485     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
486     ok(r != 0, "ret %d\n", r);
487     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
488
489     /* Set up a subitem */
490     memset (&item, 0xaa, sizeof (item));
491     item.mask = LVIF_TEXT;
492     item.iItem = 0;
493     item.iSubItem = 1;
494     item.pszText = text;
495     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
496     ok(r != 0, "ret %d\n", r);
497
498     /* Query param from subitem: returns main item param */
499     memset (&item, 0xaa, sizeof (item));
500     item.mask = LVIF_PARAM;
501     item.iItem = 0;
502     item.iSubItem = 1;
503     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
504     ok(r != 0, "ret %d\n", r);
505     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
506
507     /* Set up param on first subitem: no effect */
508     memset (&item, 0xaa, sizeof (item));
509     item.mask = LVIF_PARAM;
510     item.iItem = 0;
511     item.iSubItem = 1;
512     item.lParam = lparamTest+1;
513     r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
514     ok(r == 0, "ret %d\n", r);
515
516     /* Query param from subitem again: should still return main item param */
517     memset (&item, 0xaa, sizeof (item));
518     item.mask = LVIF_PARAM;
519     item.iItem = 0;
520     item.iSubItem = 1;
521     r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
522     ok(r != 0, "ret %d\n", r);
523     ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
524
525     /**** Some tests of state highlighting ****/
526     memset (&item, 0xaa, sizeof (item));
527     item.mask = LVIF_STATE;
528     item.iItem = 0;
529     item.iSubItem = 0;
530     item.state = LVIS_SELECTED;
531     item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
532     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
533     ok(r != 0, "ret %d\n", r);
534     item.iSubItem = 1;
535     item.state = LVIS_DROPHILITED;
536     r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
537     ok(r != 0, "ret %d\n", r);
538
539     memset (&item, 0xaa, sizeof (item));
540     item.mask = LVIF_STATE;
541     item.iItem = 0;
542     item.iSubItem = 0;
543     item.stateMask = -1;
544     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
545     ok(r != 0, "ret %d\n", r);
546     ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
547     item.iSubItem = 1;
548     r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
549     ok(r != 0, "ret %d\n", r);
550     todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
551
552     DestroyWindow(hwnd);
553 }
554
555 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
556 static WNDPROC listviewWndProc;
557 static HIMAGELIST test_create_imagelist;
558
559 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
560 {
561     if (uMsg == WM_CREATE)
562     {
563         LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
564         lpcs->style |= LVS_REPORT;
565         SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
566     }
567     return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
568 }
569
570 static void test_create(void)
571 {
572     HWND hList;
573     HWND hHeader;
574     WNDCLASSEX cls;
575     cls.cbSize = sizeof(WNDCLASSEX);
576     ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
577     listviewWndProc = cls.lpfnWndProc;
578     cls.lpfnWndProc = create_test_wndproc;
579     cls.lpszClassName = "MyListView32";
580     ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
581
582     test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
583     hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
584     ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
585     hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
586     ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
587     DestroyWindow(hList);
588 }
589
590 static void test_redraw(void)
591 {
592     HWND hwnd, hwndheader;
593
594     hwnd = create_listview_control();
595     hwndheader = subclass_header(hwnd);
596
597     flush_sequences(sequences, NUM_MSG_SEQUENCES);
598
599     trace("invalidate & update\n");
600     InvalidateRect(hwnd, NULL, TRUE);
601     UpdateWindow(hwnd);
602     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
603
604     flush_sequences(sequences, NUM_MSG_SEQUENCES);
605
606     DestroyWindow(hwnd);
607 }
608
609 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
610 {
611     COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
612
613     if(msg == WM_NOTIFY) {
614         NMHDR *nmhdr = (PVOID)lp;
615         if(nmhdr->code == NM_CUSTOMDRAW) {
616             NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
617             trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
618             switch(nmlvcd->nmcd.dwDrawStage) {
619             case CDDS_PREPAINT:
620                 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
621                 return CDRF_NOTIFYITEMDRAW;
622             case CDDS_ITEMPREPAINT:
623                 nmlvcd->clrTextBk = CLR_DEFAULT;
624                 return CDRF_NOTIFYSUBITEMDRAW;
625             case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
626                 clr = GetBkColor(nmlvcd->nmcd.hdc);
627                 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
628                 return CDRF_NOTIFYPOSTPAINT;
629             case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
630                 clr = GetBkColor(nmlvcd->nmcd.hdc);
631                 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
632                 return CDRF_DODEFAULT;
633             }
634             return CDRF_DODEFAULT;
635         }
636     }
637
638     return DefWindowProcA(hwnd, msg, wp, lp);
639 }
640
641 static void test_customdraw(void)
642 {
643     HWND hwnd;
644     WNDPROC oldwndproc;
645
646     hwnd = create_listview_control();
647
648     insert_column(hwnd, 0);
649     insert_column(hwnd, 1);
650     insert_item(hwnd, 0);
651
652     oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWL_WNDPROC,
653                                            (INT_PTR)cd_wndproc);
654
655     InvalidateRect(hwnd, NULL, TRUE);
656     UpdateWindow(hwnd);
657
658     SetWindowLongPtr(hwndparent, GWL_WNDPROC, (INT_PTR)oldwndproc);
659
660     DestroyWindow(hwnd);
661 }
662
663 START_TEST(listview)
664 {
665     INITCOMMONCONTROLSEX icc;
666
667     icc.dwICC = 0;
668     icc.dwSize = sizeof icc;
669     InitCommonControlsEx(&icc);
670
671     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
672
673     hwndparent = create_parent_window();
674
675     test_images();
676     test_checkboxes();
677     test_items();
678     test_create();
679     test_redraw();
680     test_customdraw();
681 }