comctl32: Remove clrTextBkDefault member from LISTVIEW_INFO and fix (clrTextBk =...
[wine/hacks.git] / dlls / comctl32 / tests / listview.c
blob32b9646fa27668f8529c1aafbe802fad29bfd15e
1 /*
2 * ListView tests
4 * Copyright 2006 Mike McCormack for CodeWeavers
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.
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.
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
21 #include <stdio.h>
22 #include <windows.h>
23 #include <commctrl.h>
25 #include "wine/test.h"
26 #include "msg.h"
28 #define PARENT_SEQ_INDEX 0
29 #define LISTVIEW_SEQ_INDEX 1
30 #define NUM_MSG_SEQUENCES 2
32 #define LISTVIEW_ID 0
33 #define HEADER_ID 1
35 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
37 HWND hwndparent;
39 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
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 }
52 struct subclass_info
54 WNDPROC oldproc;
57 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
59 static long defwndproc_counter = 0;
60 LRESULT ret;
61 struct message msg;
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)
72 trace("parent: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
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);
82 defwndproc_counter++;
83 ret = DefWindowProcA(hwnd, message, wParam, lParam);
84 defwndproc_counter--;
86 return ret;
89 static BOOL register_parent_wnd_class(void)
91 WNDCLASSA cls;
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);
106 static HWND create_parent_window(void)
108 if (!register_parent_wnd_class())
109 return NULL;
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);
119 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
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;
126 trace("listview: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
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);
136 defwndproc_counter++;
137 ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
138 defwndproc_counter--;
139 return ret;
142 static HWND create_listview_control()
144 struct subclass_info *info;
145 HWND hwnd;
146 RECT rect;
148 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
149 if (!info)
150 return NULL;
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());
159 if (!hwnd)
161 HeapFree(GetProcessHeap(), 0, info);
162 return NULL;
165 info->oldproc = (WNDPROC)SetWindowLongA(hwnd, GWL_WNDPROC,
166 (LONG)listview_subclass_proc);
167 SetWindowLongA(hwnd, GWL_USERDATA, (LONG)info);
169 return hwnd;
172 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
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;
179 trace("header: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);
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);
189 defwndproc_counter++;
190 ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
191 defwndproc_counter--;
192 return ret;
195 static HWND subclass_header(HWND hwndListview)
197 struct subclass_info *info;
198 HWND hwnd;
200 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
201 if (!info)
202 return NULL;
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);
209 return hwnd;
212 static void test_images(void)
214 HWND hwnd;
215 DWORD r;
216 LVITEM item;
217 HIMAGELIST himl;
218 HBITMAP hbmp;
219 RECT r1, r2;
220 static CHAR hello[] = "hello";
222 himl = ImageList_Create(40, 40, 0, 4, 4);
223 ok(himl != NULL, "failed to create imagelist\n");
225 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
226 ok(hbmp != NULL, "failed to create bitmap\n");
228 r = ImageList_Add(himl, hbmp, 0);
229 ok(r == 0, "should be zero\n");
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");
235 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
236 ok(r == 0, "should return zero\n");
238 r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
239 ok(r == 0, "should return zero\n");
241 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
242 /* returns dimensions */
244 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
245 ok(r == 0, "should be zero items\n");
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");
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");
260 memset(&r1, 0, sizeof r1);
261 r1.left = LVIR_ICON;
262 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
264 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
265 ok(r == TRUE, "should not fail\n");
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");
272 memset(&r2, 0, sizeof r2);
273 r2.left = LVIR_ICON;
274 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
276 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
278 DestroyWindow(hwnd);
281 static void test_checkboxes(void)
283 HWND hwnd;
284 LVITEMA item;
285 DWORD r;
286 static CHAR text[] = "Text",
287 text2[] = "Text2",
288 text3[] = "Text3";
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");
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);
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);
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);
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);
326 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
327 ok(r == 0, "should return zero\n");
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);
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);
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);
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);
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);
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);
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);
378 /* Check that only the bits we asked for are returned,
379 * and that all the others are set to zero
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);
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);
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);
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);
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);
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);
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);
418 DestroyWindow(hwnd);
421 static void insert_column(HWND hwnd, int idx)
423 LVCOLUMN column;
424 DWORD rc;
426 memset(&column, 0xaa, sizeof(column));
427 column.mask = LVCF_SUBITEM;
428 column.iSubItem = idx;
430 rc = ListView_InsertColumn(hwnd, idx, &column);
431 expect(idx, rc);
434 static void insert_item(HWND hwnd, int idx)
436 static CHAR text[] = "foo";
438 LVITEMA item;
439 DWORD rc;
441 memset(&item, 0xaa, sizeof (item));
442 item.mask = LVIF_TEXT;
443 item.iItem = idx;
444 item.iSubItem = 0;
445 item.pszText = text;
447 rc = ListView_InsertItemA(hwnd, &item);
448 expect(idx, rc);
451 static void test_items(void)
453 const LPARAM lparamTest = 0x42;
454 HWND hwnd;
455 LVITEMA item;
456 DWORD r;
457 static CHAR text[] = "Text";
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");
464 * Test setting/getting item params
467 /* Set up two columns */
468 insert_column(hwnd, 0);
469 insert_column(hwnd, 1);
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);
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);
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);
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);
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);
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);
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);
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);
552 DestroyWindow(hwnd);
555 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
556 static WNDPROC listviewWndProc;
557 static HIMAGELIST test_create_imagelist;
559 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
561 if (uMsg == WM_CREATE)
563 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
564 lpcs->style |= LVS_REPORT;
565 SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
567 return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
570 static void test_create()
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");
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);
590 static void test_redraw(void)
592 HWND hwnd, hwndheader;
594 hwnd = create_listview_control();
595 hwndheader = subclass_header(hwnd);
597 flush_sequences(sequences, NUM_MSG_SEQUENCES);
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);
604 flush_sequences(sequences, NUM_MSG_SEQUENCES);
606 DestroyWindow(hwnd);
609 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
611 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
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 ok(clr == c0ffee, "clr=%.8x\n", clr);
628 return CDRF_NOTIFYPOSTPAINT;
629 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
630 clr = GetBkColor(nmlvcd->nmcd.hdc);
631 ok(clr == c0ffee, "clr=%.8x\n", clr);
632 return CDRF_DODEFAULT;
634 return CDRF_DODEFAULT;
638 return DefWindowProcA(hwnd, msg, wp, lp);
641 static void test_customdraw(void)
643 HWND hwnd;
644 WNDPROC oldwndproc;
646 hwnd = create_listview_control();
648 insert_column(hwnd, 0);
649 insert_column(hwnd, 1);
650 insert_item(hwnd, 0);
652 oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWL_WNDPROC,
653 (INT_PTR)cd_wndproc);
655 InvalidateRect(hwnd, NULL, TRUE);
656 UpdateWindow(hwnd);
658 SetWindowLongPtr(hwndparent, GWL_WNDPROC, (INT_PTR)oldwndproc);
660 DestroyWindow(hwnd);
663 START_TEST(listview)
665 INITCOMMONCONTROLSEX icc;
667 icc.dwICC = 0;
668 icc.dwSize = sizeof icc;
669 InitCommonControlsEx(&icc);
671 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
673 hwndparent = create_parent_window();
675 test_images();
676 test_checkboxes();
677 test_items();
678 test_create();
679 test_redraw();
680 test_customdraw();