Merge from amd64-branch:
[reactos.git] / rostests / winetests / comctl32 / 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 PARENT_FULL_SEQ_INDEX 1
31 #define LISTVIEW_SEQ_INDEX 2
32 #define NUM_MSG_SEQUENCES 3
33
34 #define LISTVIEW_ID 0
35 #define HEADER_ID 1
36
37 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
38 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
39 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
40
41 HWND hwndparent;
42
43 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
44
45 static const struct message create_parent_wnd_seq[] = {
46 { WM_GETMINMAXINFO, sent },
47 { WM_NCCREATE, sent },
48 { WM_NCCALCSIZE, sent|wparam, 0 },
49 { WM_CREATE, sent },
50 { WM_SHOWWINDOW, sent|wparam, 1 },
51 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
52 { WM_QUERYNEWPALETTE, sent|optional },
53 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
54 { WM_WINDOWPOSCHANGED, sent|optional },
55 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
56 { WM_ACTIVATEAPP, sent|wparam, 1 },
57 { WM_NCACTIVATE, sent|wparam, 1 },
58 { WM_ACTIVATE, sent|wparam, 1 },
59 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
60 { WM_IME_NOTIFY, sent|defwinproc|optional },
61 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
62 /* Win9x adds SWP_NOZORDER below */
63 { WM_WINDOWPOSCHANGED, sent, /*|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ },
64 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
65 { WM_SIZE, sent },
66 { WM_MOVE, sent },
67 { 0 }
68 };
69
70 static const struct message redraw_listview_seq[] = {
71 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
72 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
73 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
74 { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, HEADER_ID },
75 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
76 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
77 { WM_ERASEBKGND, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
78 { 0 }
79 };
80
81 static const struct message listview_icon_spacing_seq[] = {
82 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
83 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
84 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
85 { 0 }
86 };
87
88 static const struct message listview_color_seq[] = {
89 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
90 { LVM_GETBKCOLOR, sent },
91 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
92 { LVM_GETTEXTCOLOR, sent },
93 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
94 { LVM_GETTEXTBKCOLOR, sent },
95
96 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
97 { LVM_GETBKCOLOR, sent },
98 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
99 { LVM_GETTEXTCOLOR, sent },
100 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
101 { LVM_GETTEXTBKCOLOR, sent },
102
103 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
104 { LVM_GETBKCOLOR, sent },
105 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
106 { LVM_GETTEXTCOLOR, sent },
107 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
108 { LVM_GETTEXTBKCOLOR, sent },
109
110 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
111 { LVM_GETBKCOLOR, sent },
112 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
113 { LVM_GETTEXTCOLOR, sent },
114 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
115 { LVM_GETTEXTBKCOLOR, sent },
116 { 0 }
117 };
118
119 static const struct message listview_item_count_seq[] = {
120 { LVM_GETITEMCOUNT, sent },
121 { LVM_INSERTITEM, sent },
122 { LVM_INSERTITEM, sent },
123 { LVM_INSERTITEM, sent },
124 { LVM_GETITEMCOUNT, sent },
125 { LVM_DELETEITEM, sent|wparam, 2 },
126 { LVM_GETITEMCOUNT, sent },
127 { LVM_DELETEALLITEMS, sent },
128 { LVM_GETITEMCOUNT, sent },
129 { LVM_INSERTITEM, sent },
130 { LVM_INSERTITEM, sent },
131 { LVM_GETITEMCOUNT, sent },
132 { LVM_INSERTITEM, sent },
133 { LVM_GETITEMCOUNT, sent },
134 { 0 }
135 };
136
137 static const struct message listview_itempos_seq[] = {
138 { LVM_INSERTITEM, sent },
139 { LVM_INSERTITEM, sent },
140 { LVM_INSERTITEM, sent },
141 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
142 { LVM_GETITEMPOSITION, sent|wparam, 1 },
143 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
144 { LVM_GETITEMPOSITION, sent|wparam, 2 },
145 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
146 { LVM_GETITEMPOSITION, sent|wparam, 0 },
147 { 0 }
148 };
149
150 static const struct message listview_ownerdata_switchto_seq[] = {
151 { WM_STYLECHANGING, sent },
152 { WM_STYLECHANGED, sent },
153 { 0 }
154 };
155
156 static const struct message listview_getorderarray_seq[] = {
157 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
158 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
159 { 0 }
160 };
161
162 static const struct message empty_seq[] = {
163 { 0 }
164 };
165
166 static const struct message forward_erasebkgnd_parent_seq[] = {
167 { WM_ERASEBKGND, sent },
168 { 0 }
169 };
170
171 struct subclass_info
172 {
173 WNDPROC oldproc;
174 };
175
176 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
177 {
178 static LONG defwndproc_counter = 0;
179 LRESULT ret;
180 struct message msg;
181
182 msg.message = message;
183 msg.flags = sent|wparam|lparam;
184 if (defwndproc_counter) msg.flags |= defwinproc;
185 msg.wParam = wParam;
186 msg.lParam = lParam;
187
188 /* log system messages, except for painting */
189 if (message < WM_USER &&
190 message != WM_PAINT &&
191 message != WM_ERASEBKGND &&
192 message != WM_NCPAINT &&
193 message != WM_NCHITTEST &&
194 message != WM_GETTEXT &&
195 message != WM_GETICON &&
196 message != WM_DEVICECHANGE)
197 {
198 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
199
200 add_message(sequences, PARENT_SEQ_INDEX, &msg);
201 }
202 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
203
204 defwndproc_counter++;
205 ret = DefWindowProcA(hwnd, message, wParam, lParam);
206 defwndproc_counter--;
207
208 return ret;
209 }
210
211 static BOOL register_parent_wnd_class(void)
212 {
213 WNDCLASSA cls;
214
215 cls.style = 0;
216 cls.lpfnWndProc = parent_wnd_proc;
217 cls.cbClsExtra = 0;
218 cls.cbWndExtra = 0;
219 cls.hInstance = GetModuleHandleA(NULL);
220 cls.hIcon = 0;
221 cls.hCursor = LoadCursorA(0, IDC_ARROW);
222 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
223 cls.lpszMenuName = NULL;
224 cls.lpszClassName = "Listview test parent class";
225 return RegisterClassA(&cls);
226 }
227
228 static HWND create_parent_window(void)
229 {
230 if (!register_parent_wnd_class())
231 return NULL;
232
233 return CreateWindowEx(0, "Listview test parent class",
234 "Listview test parent window",
235 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
236 WS_MAXIMIZEBOX | WS_VISIBLE,
237 0, 0, 100, 100,
238 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
239 }
240
241 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
242 {
243 struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
244 static LONG defwndproc_counter = 0;
245 LRESULT ret;
246 struct message msg;
247
248 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
249
250 /* some debug output for style changing */
251 if ((message == WM_STYLECHANGING ||
252 message == WM_STYLECHANGED) && lParam)
253 {
254 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
255 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
256 }
257
258 msg.message = message;
259 msg.flags = sent|wparam|lparam;
260 if (defwndproc_counter) msg.flags |= defwinproc;
261 msg.wParam = wParam;
262 msg.lParam = lParam;
263 msg.id = LISTVIEW_ID;
264 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
265
266 defwndproc_counter++;
267 ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
268 defwndproc_counter--;
269 return ret;
270 }
271
272 static HWND create_listview_control(DWORD style)
273 {
274 struct subclass_info *info;
275 HWND hwnd;
276 RECT rect;
277
278 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
279 if (!info)
280 return NULL;
281
282 GetClientRect(hwndparent, &rect);
283 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
284 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style,
285 0, 0, rect.right, rect.bottom,
286 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
287 ok(hwnd != NULL, "gle=%d\n", GetLastError());
288
289 if (!hwnd)
290 {
291 HeapFree(GetProcessHeap(), 0, info);
292 return NULL;
293 }
294
295 info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
296 (LONG_PTR)listview_subclass_proc);
297 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
298
299 return hwnd;
300 }
301
302 static HWND create_custom_listview_control(DWORD style)
303 {
304 struct subclass_info *info;
305 HWND hwnd;
306 RECT rect;
307
308 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
309 if (!info)
310 return NULL;
311
312 GetClientRect(hwndparent, &rect);
313 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
314 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
315 0, 0, rect.right, rect.bottom,
316 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
317 ok(hwnd != NULL, "gle=%d\n", GetLastError());
318
319 if (!hwnd)
320 {
321 HeapFree(GetProcessHeap(), 0, info);
322 return NULL;
323 }
324
325 info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
326 (LONG_PTR)listview_subclass_proc);
327 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
328
329 return hwnd;
330 }
331
332 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
333 {
334 struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
335 static LONG defwndproc_counter = 0;
336 LRESULT ret;
337 struct message msg;
338
339 trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
340
341 msg.message = message;
342 msg.flags = sent|wparam|lparam;
343 if (defwndproc_counter) msg.flags |= defwinproc;
344 msg.wParam = wParam;
345 msg.lParam = lParam;
346 msg.id = HEADER_ID;
347 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
348
349 defwndproc_counter++;
350 ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
351 defwndproc_counter--;
352 return ret;
353 }
354
355 static HWND subclass_header(HWND hwndListview)
356 {
357 struct subclass_info *info;
358 HWND hwnd;
359
360 info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
361 if (!info)
362 return NULL;
363
364 hwnd = ListView_GetHeader(hwndListview);
365 info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
366 (LONG_PTR)header_subclass_proc);
367 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
368
369 return hwnd;
370 }
371
372 static void test_images(void)
373 {
374 HWND hwnd;
375 DWORD r;
376 LVITEM item;
377 HIMAGELIST himl;
378 HBITMAP hbmp;
379 RECT r1, r2;
380 static CHAR hello[] = "hello";
381
382 himl = ImageList_Create(40, 40, 0, 4, 4);
383 ok(himl != NULL, "failed to create imagelist\n");
384
385 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
386 ok(hbmp != NULL, "failed to create bitmap\n");
387
388 r = ImageList_Add(himl, hbmp, 0);
389 ok(r == 0, "should be zero\n");
390
391 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
392 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
393 ok(hwnd != NULL, "failed to create listview window\n");
394
395 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
396 ok(r == 0, "should return zero\n");
397
398 r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
399 ok(r == 0, "should return zero\n");
400
401 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
402 /* returns dimensions */
403
404 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
405 ok(r == 0, "should be zero items\n");
406
407 item.mask = LVIF_IMAGE | LVIF_TEXT;
408 item.iItem = 0;
409 item.iSubItem = 1;
410 item.iImage = 0;
411 item.pszText = 0;
412 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
413 ok(r == -1, "should fail\n");
414
415 item.iSubItem = 0;
416 item.pszText = hello;
417 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
418 ok(r == 0, "should not fail\n");
419
420 memset(&r1, 0, sizeof r1);
421 r1.left = LVIR_ICON;
422 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
423
424 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
425 ok(r == TRUE, "should not fail\n");
426
427 item.iSubItem = 0;
428 item.pszText = hello;
429 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
430 ok(r == 0, "should not fail\n");
431
432 memset(&r2, 0, sizeof r2);
433 r2.left = LVIR_ICON;
434 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
435
436 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
437
438 DestroyWindow(hwnd);
439 }
440
441 static void test_checkboxes(void)
442 {
443 HWND hwnd;
444 LVITEMA item;
445 DWORD r;
446 static CHAR text[] = "Text",
447 text2[] = "Text2",
448 text3[] = "Text3";
449
450 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
451 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
452 ok(hwnd != NULL, "failed to create listview window\n");
453
454 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
455 item.mask = LVIF_TEXT | LVIF_STATE;
456 item.stateMask = 0xffff;
457 item.state = 0xfccc;
458 item.iItem = 0;
459 item.iSubItem = 0;
460 item.pszText = text;
461 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
462 ok(r == 0, "ret %d\n", r);
463
464 item.iItem = 0;
465 item.mask = LVIF_STATE;
466 item.stateMask = 0xffff;
467 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
468 ok(item.state == 0xfccc, "state %x\n", item.state);
469
470 /* Don't set LVIF_STATE */
471 item.mask = LVIF_TEXT;
472 item.stateMask = 0xffff;
473 item.state = 0xfccc;
474 item.iItem = 1;
475 item.iSubItem = 0;
476 item.pszText = text;
477 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
478 ok(r == 1, "ret %d\n", r);
479
480 item.iItem = 1;
481 item.mask = LVIF_STATE;
482 item.stateMask = 0xffff;
483 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
484 ok(item.state == 0, "state %x\n", item.state);
485
486 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
487 ok(r == 0, "should return zero\n");
488
489 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
490 item.iItem = 0;
491 item.mask = LVIF_STATE;
492 item.stateMask = 0xffff;
493 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
494 ok(item.state == 0x1ccc, "state %x\n", item.state);
495
496 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
497 item.iItem = 2;
498 item.mask = LVIF_TEXT;
499 item.state = 0;
500 item.pszText = text2;
501 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
502 ok(r == 2, "ret %d\n", r);
503
504 item.iItem = 2;
505 item.mask = LVIF_STATE;
506 item.stateMask = 0xffff;
507 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
508 ok(item.state == 0x1000, "state %x\n", item.state);
509
510 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
511 item.iItem = 3;
512 item.mask = LVIF_TEXT | LVIF_STATE;
513 item.stateMask = 0xffff;
514 item.state = 0x2aaa;
515 item.pszText = text3;
516 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
517 ok(r == 3, "ret %d\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 == 0x1aaa, "state %x\n", item.state);
524
525 /* Set an item's state to checked */
526 item.iItem = 3;
527 item.mask = LVIF_STATE;
528 item.stateMask = 0xf000;
529 item.state = 0x2000;
530 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
531
532 item.iItem = 3;
533 item.mask = LVIF_STATE;
534 item.stateMask = 0xffff;
535 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
536 ok(item.state == 0x2aaa, "state %x\n", item.state);
537
538 /* Check that only the bits we asked for are returned,
539 * and that all the others are set to zero
540 */
541 item.iItem = 3;
542 item.mask = LVIF_STATE;
543 item.stateMask = 0xf000;
544 item.state = 0xffff;
545 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
546 ok(item.state == 0x2000, "state %x\n", item.state);
547
548 /* Set the style again and check that doesn't change an item's state */
549 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
550 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
551
552 item.iItem = 3;
553 item.mask = LVIF_STATE;
554 item.stateMask = 0xffff;
555 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
556 ok(item.state == 0x2aaa, "state %x\n", item.state);
557
558 /* Unsetting the checkbox extended style doesn't change an item's state */
559 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
560 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
561
562 item.iItem = 3;
563 item.mask = LVIF_STATE;
564 item.stateMask = 0xffff;
565 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
566 ok(item.state == 0x2aaa, "state %x\n", item.state);
567
568 /* Now setting the style again will change an item's state */
569 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
570 ok(r == 0, "ret %x\n", r);
571
572 item.iItem = 3;
573 item.mask = LVIF_STATE;
574 item.stateMask = 0xffff;
575 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
576 ok(item.state == 0x1aaa, "state %x\n", item.state);
577
578 /* Toggle checkbox tests (bug 9934) */
579 memset (&item, 0xcc, sizeof(item));
580 item.mask = LVIF_STATE;
581 item.iItem = 3;
582 item.iSubItem = 0;
583 item.state = LVIS_FOCUSED;
584 item.stateMask = LVIS_FOCUSED;
585 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
586 expect(1, r);
587
588 item.iItem = 3;
589 item.mask = LVIF_STATE;
590 item.stateMask = 0xffff;
591 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
592 ok(item.state == 0x1aab, "state %x\n", item.state);
593
594 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
595 expect(0, r);
596 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
597 expect(0, r);
598
599 item.iItem = 3;
600 item.mask = LVIF_STATE;
601 item.stateMask = 0xffff;
602 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
603 ok(item.state == 0x2aab, "state %x\n", item.state);
604
605 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
606 expect(0, r);
607 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
608 expect(0, r);
609
610 item.iItem = 3;
611 item.mask = LVIF_STATE;
612 item.stateMask = 0xffff;
613 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
614 ok(item.state == 0x1aab, "state %x\n", item.state);
615
616 DestroyWindow(hwnd);
617 }
618
619 static void insert_column(HWND hwnd, int idx)
620 {
621 LVCOLUMN column;
622 DWORD rc;
623
624 memset(&column, 0xcc, sizeof(column));
625 column.mask = LVCF_SUBITEM;
626 column.iSubItem = idx;
627
628 rc = ListView_InsertColumn(hwnd, idx, &column);
629 expect(idx, rc);
630 }
631
632 static void insert_item(HWND hwnd, int idx)
633 {
634 static CHAR text[] = "foo";
635
636 LVITEMA item;
637 DWORD rc;
638
639 memset(&item, 0xcc, sizeof (item));
640 item.mask = LVIF_TEXT;
641 item.iItem = idx;
642 item.iSubItem = 0;
643 item.pszText = text;
644
645 rc = ListView_InsertItem(hwnd, &item);
646 expect(idx, rc);
647 }
648
649 static void test_items(void)
650 {
651 const LPARAM lparamTest = 0x42;
652 HWND hwnd;
653 LVITEMA item;
654 DWORD r;
655 static CHAR text[] = "Text";
656
657 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
658 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
659 ok(hwnd != NULL, "failed to create listview window\n");
660
661 /*
662 * Test setting/getting item params
663 */
664
665 /* Set up two columns */
666 insert_column(hwnd, 0);
667 insert_column(hwnd, 1);
668
669 /* LVIS_SELECTED with zero stateMask */
670 /* set */
671 memset (&item, 0, sizeof (item));
672 item.mask = LVIF_STATE;
673 item.state = LVIS_SELECTED;
674 item.stateMask = 0;
675 item.iItem = 0;
676 item.iSubItem = 0;
677 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
678 ok(r == 0, "ret %d\n", r);
679 /* get */
680 memset (&item, 0xcc, sizeof (item));
681 item.mask = LVIF_STATE;
682 item.stateMask = LVIS_SELECTED;
683 item.state = 0;
684 item.iItem = 0;
685 item.iSubItem = 0;
686 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
687 ok(r != 0, "ret %d\n", r);
688 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
689 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
690
691 /* LVIS_SELECTED with zero stateMask */
692 /* set */
693 memset (&item, 0, sizeof (item));
694 item.mask = LVIF_STATE;
695 item.state = LVIS_FOCUSED;
696 item.stateMask = 0;
697 item.iItem = 0;
698 item.iSubItem = 0;
699 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
700 ok(r == 0, "ret %d\n", r);
701 /* get */
702 memset (&item, 0xcc, sizeof (item));
703 item.mask = LVIF_STATE;
704 item.stateMask = LVIS_FOCUSED;
705 item.state = 0;
706 item.iItem = 0;
707 item.iSubItem = 0;
708 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
709 ok(r != 0, "ret %d\n", r);
710 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
711 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
712
713 /* LVIS_CUT with LVIS_FOCUSED stateMask */
714 /* set */
715 memset (&item, 0, sizeof (item));
716 item.mask = LVIF_STATE;
717 item.state = LVIS_CUT;
718 item.stateMask = LVIS_FOCUSED;
719 item.iItem = 0;
720 item.iSubItem = 0;
721 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
722 ok(r == 0, "ret %d\n", r);
723 /* get */
724 memset (&item, 0xcc, sizeof (item));
725 item.mask = LVIF_STATE;
726 item.stateMask = LVIS_CUT;
727 item.state = 0;
728 item.iItem = 0;
729 item.iSubItem = 0;
730 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
731 ok(r != 0, "ret %d\n", r);
732 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
733 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
734
735 /* Insert an item with just a param */
736 memset (&item, 0xcc, sizeof (item));
737 item.mask = LVIF_PARAM;
738 item.iItem = 0;
739 item.iSubItem = 0;
740 item.lParam = lparamTest;
741 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
742 ok(r == 0, "ret %d\n", r);
743
744 /* Test getting of the param */
745 memset (&item, 0xcc, sizeof (item));
746 item.mask = LVIF_PARAM;
747 item.iItem = 0;
748 item.iSubItem = 0;
749 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
750 ok(r != 0, "ret %d\n", r);
751 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
752
753 /* Set up a subitem */
754 memset (&item, 0xcc, sizeof (item));
755 item.mask = LVIF_TEXT;
756 item.iItem = 0;
757 item.iSubItem = 1;
758 item.pszText = text;
759 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
760 ok(r != 0, "ret %d\n", r);
761
762 /* Query param from subitem: returns main item param */
763 memset (&item, 0xcc, sizeof (item));
764 item.mask = LVIF_PARAM;
765 item.iItem = 0;
766 item.iSubItem = 1;
767 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
768 ok(r != 0, "ret %d\n", r);
769 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
770
771 /* Set up param on first subitem: no effect */
772 memset (&item, 0xcc, sizeof (item));
773 item.mask = LVIF_PARAM;
774 item.iItem = 0;
775 item.iSubItem = 1;
776 item.lParam = lparamTest+1;
777 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
778 ok(r == 0, "ret %d\n", r);
779
780 /* Query param from subitem again: should still return main item param */
781 memset (&item, 0xcc, sizeof (item));
782 item.mask = LVIF_PARAM;
783 item.iItem = 0;
784 item.iSubItem = 1;
785 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
786 ok(r != 0, "ret %d\n", r);
787 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
788
789 /**** Some tests of state highlighting ****/
790 memset (&item, 0xcc, sizeof (item));
791 item.mask = LVIF_STATE;
792 item.iItem = 0;
793 item.iSubItem = 0;
794 item.state = LVIS_SELECTED;
795 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
796 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
797 ok(r != 0, "ret %d\n", r);
798 item.iSubItem = 1;
799 item.state = LVIS_DROPHILITED;
800 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
801 ok(r != 0, "ret %d\n", r);
802
803 memset (&item, 0xcc, sizeof (item));
804 item.mask = LVIF_STATE;
805 item.iItem = 0;
806 item.iSubItem = 0;
807 item.stateMask = -1;
808 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
809 ok(r != 0, "ret %d\n", r);
810 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
811 item.iSubItem = 1;
812 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
813 ok(r != 0, "ret %d\n", r);
814 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
815
816 /* some notnull but meaningless masks */
817 memset (&item, 0, sizeof(item));
818 item.mask = LVIF_NORECOMPUTE;
819 item.iItem = 0;
820 item.iSubItem = 0;
821 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
822 ok(r != 0, "ret %d\n", r);
823 memset (&item, 0, sizeof(item));
824 item.mask = LVIF_DI_SETITEM;
825 item.iItem = 0;
826 item.iSubItem = 0;
827 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
828 ok(r != 0, "ret %d\n", r);
829
830 DestroyWindow(hwnd);
831 }
832
833 static void test_columns(void)
834 {
835 HWND hwnd, hwndheader;
836 LVCOLUMN column;
837 DWORD rc;
838 INT order[2];
839
840 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
841 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
842 ok(hwnd != NULL, "failed to create listview window\n");
843
844 /* Add a column with no mask */
845 memset(&column, 0xcc, sizeof(column));
846 column.mask = 0;
847 rc = ListView_InsertColumn(hwnd, 0, &column);
848 ok(rc==0, "Inserting column with no mask failed with %d\n", rc);
849
850 /* Check its width */
851 rc = ListView_GetColumnWidth(hwnd, 0);
852 ok(rc==10 ||
853 broken(rc==0), /* win9x */
854 "Inserting column with no mask failed to set width to 10 with %d\n", rc);
855
856 DestroyWindow(hwnd);
857
858 /* LVM_GETCOLUMNORDERARRAY */
859 hwnd = create_listview_control(0);
860 hwndheader = subclass_header(hwnd);
861
862 memset(&column, 0, sizeof(column));
863 column.mask = LVCF_WIDTH;
864 column.cx = 100;
865 rc = ListView_InsertColumn(hwnd, 0, &column);
866 ok(rc == 0, "Inserting column failed with %d\n", rc);
867
868 column.cx = 200;
869 rc = ListView_InsertColumn(hwnd, 1, &column);
870 ok(rc == 1, "Inserting column failed with %d\n", rc);
871
872 flush_sequences(sequences, NUM_MSG_SEQUENCES);
873
874 rc = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
875 ok(rc != 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
876 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
877 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
878
879 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
880
881 DestroyWindow(hwnd);
882 }
883 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
884 static WNDPROC listviewWndProc;
885 static HIMAGELIST test_create_imagelist;
886
887 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
888 {
889 LRESULT ret;
890
891 if (uMsg == WM_CREATE)
892 {
893 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
894 lpcs->style |= LVS_REPORT;
895 }
896 ret = CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
897 if (uMsg == WM_CREATE) SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
898 return ret;
899 }
900
901 static void test_create(void)
902 {
903 HWND hList;
904 HWND hHeader;
905 LONG_PTR ret;
906 LONG r;
907 LVCOLUMNA col;
908 RECT rect;
909 WNDCLASSEX cls;
910 cls.cbSize = sizeof(WNDCLASSEX);
911 ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
912 listviewWndProc = cls.lpfnWndProc;
913 cls.lpfnWndProc = create_test_wndproc;
914 cls.lpszClassName = "MyListView32";
915 ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
916
917 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
918 hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
919 ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
920 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
921 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
922 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
923 DestroyWindow(hList);
924
925 /* header isn't created on LVS_ICON and LVS_LIST styles */
926 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
927 GetModuleHandle(NULL), 0);
928 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
929 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
930 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
931 /* insert column */
932 memset(&col, 0, sizeof(LVCOLUMNA));
933 col.mask = LVCF_WIDTH;
934 col.cx = 100;
935 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
936 ok(r == 0, "Expected 0 column's inserted\n");
937 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
938 ok(IsWindow(hHeader), "Header should be created\n");
939 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
940 DestroyWindow(hList);
941
942 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
943 GetModuleHandle(NULL), 0);
944 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
945 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
946 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
947 /* insert column */
948 memset(&col, 0, sizeof(LVCOLUMNA));
949 col.mask = LVCF_WIDTH;
950 col.cx = 100;
951 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
952 ok(r == 0, "Expected 0 column's inserted\n");
953 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
954 ok(IsWindow(hHeader), "Header should be created\n");
955 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
956 DestroyWindow(hList);
957
958 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
959 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
960 GetModuleHandle(NULL), 0);
961 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLongPtr(hList, GWL_STYLE) | LVS_REPORT);
962 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
963 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
964 ok(IsWindow(hHeader), "Header should be created\n");
965 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLong(hList, GWL_STYLE) & ~LVS_REPORT);
966 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
967 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
968 ok(IsWindow(hHeader), "Header should be created\n");
969 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
970 DestroyWindow(hList);
971
972 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
973 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
974 GetModuleHandle(NULL), 0);
975 ret = SetWindowLongPtr(hList, GWL_STYLE,
976 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
977 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
978 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
979 ok(IsWindow(hHeader), "Header should be created\n");
980 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
981 ret = SetWindowLongPtr(hList, GWL_STYLE,
982 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
983 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
984 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
985 ok(IsWindow(hHeader), "Header should be created\n");
986 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
987 DestroyWindow(hList);
988
989 /* LVS_REPORT without WS_VISIBLE */
990 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
991 GetModuleHandle(NULL), 0);
992 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
993 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
994 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
995 /* insert column */
996 memset(&col, 0, sizeof(LVCOLUMNA));
997 col.mask = LVCF_WIDTH;
998 col.cx = 100;
999 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1000 ok(r == 0, "Expected 0 column's inserted\n");
1001 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1002 ok(IsWindow(hHeader), "Header should be created\n");
1003 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1004 DestroyWindow(hList);
1005
1006 /* LVS_REPORT without WS_VISIBLE, try to show it */
1007 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1008 GetModuleHandle(NULL), 0);
1009 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1010 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1011 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1012 ShowWindow(hList, SW_SHOW);
1013 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1014 ok(IsWindow(hHeader), "Header should be created\n");
1015 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1016 DestroyWindow(hList);
1017
1018 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1019 hList = CreateWindow("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1020 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1021 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1022 ok(IsWindow(hHeader), "Header should be created\n");
1023 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1024 /* HDS_DRAGDROP set by default */
1025 ok(GetWindowLongPtr(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1026 DestroyWindow(hList);
1027
1028 /* setting LVS_EX_HEADERDRAGDROP creates header */
1029 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1030 GetModuleHandle(NULL), 0);
1031 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1032 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1033 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1034 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1035 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1036 ok(IsWindow(hHeader), "Header should be created\n");
1037 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1038 DestroyWindow(hList);
1039
1040 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1041 hList = create_custom_listview_control(0);
1042 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1043 r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1044 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1045 DestroyWindow(hList);
1046
1047 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1048 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1049 GetModuleHandle(NULL), 0);
1050 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1051 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1052
1053 rect.left = LVIR_BOUNDS;
1054 rect.top = 1;
1055 rect.right = rect.bottom = -10;
1056 r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1057 ok(r != 0, "Expected not-null LRESULT\n");
1058
1059 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1060 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1061 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1062
1063 DestroyWindow(hList);
1064 }
1065
1066 static void test_redraw(void)
1067 {
1068 HWND hwnd, hwndheader;
1069 HDC hdc;
1070 BOOL res;
1071 DWORD r;
1072
1073 hwnd = create_listview_control(0);
1074 hwndheader = subclass_header(hwnd);
1075
1076 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1077
1078 trace("invalidate & update\n");
1079 InvalidateRect(hwnd, NULL, TRUE);
1080 UpdateWindow(hwnd);
1081 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1082
1083 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1084
1085 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1086 /* 1. Without backbuffer */
1087 res = ListView_SetBkColor(hwnd, CLR_NONE);
1088 expect(TRUE, res);
1089
1090 hdc = GetWindowDC(hwndparent);
1091
1092 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1093 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1094 ok(r != 0, "Expected not zero result\n");
1095 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1096 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1097
1098 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1099 expect(TRUE, res);
1100
1101 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1102 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1103 ok(r != 0, "Expected not zero result\n");
1104 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1105 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1106
1107 /* 2. With backbuffer */
1108 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1109 LVS_EX_DOUBLEBUFFER);
1110 res = ListView_SetBkColor(hwnd, CLR_NONE);
1111 expect(TRUE, res);
1112
1113 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1114 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1115 ok(r != 0, "Expected not zero result\n");
1116 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1117 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1118
1119 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1120 expect(TRUE, res);
1121
1122 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1123 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1124 todo_wine ok(r != 0, "Expected not zero result\n");
1125 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1126 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1127
1128 ReleaseDC(hwndparent, hdc);
1129
1130 DestroyWindow(hwnd);
1131 }
1132
1133 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1134 {
1135 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1136
1137 if(msg == WM_NOTIFY) {
1138 NMHDR *nmhdr = (PVOID)lp;
1139 if(nmhdr->code == NM_CUSTOMDRAW) {
1140 NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
1141 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
1142 switch(nmlvcd->nmcd.dwDrawStage) {
1143 case CDDS_PREPAINT:
1144 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1145 return CDRF_NOTIFYITEMDRAW;
1146 case CDDS_ITEMPREPAINT:
1147 nmlvcd->clrTextBk = CLR_DEFAULT;
1148 return CDRF_NOTIFYSUBITEMDRAW;
1149 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1150 clr = GetBkColor(nmlvcd->nmcd.hdc);
1151 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1152 return CDRF_NOTIFYPOSTPAINT;
1153 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1154 clr = GetBkColor(nmlvcd->nmcd.hdc);
1155 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1156 return CDRF_DODEFAULT;
1157 }
1158 return CDRF_DODEFAULT;
1159 }
1160 }
1161
1162 return DefWindowProcA(hwnd, msg, wp, lp);
1163 }
1164
1165 static void test_customdraw(void)
1166 {
1167 HWND hwnd;
1168 WNDPROC oldwndproc;
1169
1170 hwnd = create_listview_control(0);
1171
1172 insert_column(hwnd, 0);
1173 insert_column(hwnd, 1);
1174 insert_item(hwnd, 0);
1175
1176 oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
1177 (LONG_PTR)cd_wndproc);
1178
1179 InvalidateRect(hwnd, NULL, TRUE);
1180 UpdateWindow(hwnd);
1181
1182 SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1183
1184 DestroyWindow(hwnd);
1185 }
1186
1187 static void test_icon_spacing(void)
1188 {
1189 /* LVM_SETICONSPACING */
1190 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1191
1192 HWND hwnd;
1193 WORD w, h;
1194 DWORD r;
1195
1196 hwnd = create_custom_listview_control(LVS_ICON);
1197 ok(hwnd != NULL, "failed to create a listview window\n");
1198
1199 r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY);
1200 expect(NFR_ANSI, r);
1201
1202 /* reset the icon spacing to defaults */
1203 SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1204
1205 /* now we can request what the defaults are */
1206 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1207 w = LOWORD(r);
1208 h = HIWORD(r);
1209
1210 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1211
1212 trace("test icon spacing\n");
1213
1214 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1215 ok(r == MAKELONG(w, h) ||
1216 broken(r == MAKELONG(w, w)), /* win98 */
1217 "Expected %d, got %d\n", MAKELONG(w, h), r);
1218
1219 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1220 expect(MAKELONG(20,30), r);
1221
1222 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1223 expect(MAKELONG(25,35), r);
1224
1225 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1226
1227 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1228 DestroyWindow(hwnd);
1229 }
1230
1231 static void test_color(void)
1232 {
1233 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1234
1235 HWND hwnd;
1236 DWORD r;
1237 int i;
1238
1239 COLORREF color;
1240 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1241
1242 hwnd = create_listview_control(0);
1243 ok(hwnd != NULL, "failed to create a listview window\n");
1244
1245 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1246
1247 trace("test color seq\n");
1248 for (i = 0; i < 4; i++)
1249 {
1250 color = colors[i];
1251
1252 r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
1253 expect(TRUE, r);
1254 r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color);
1255 expect(color, r);
1256
1257 r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
1258 expect (TRUE, r);
1259 r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color);
1260 expect(color, r);
1261
1262 r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1263 expect(TRUE, r);
1264 r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color);
1265 expect(color, r);
1266 }
1267
1268 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1269
1270 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1271 DestroyWindow(hwnd);
1272 }
1273
1274 static void test_item_count(void)
1275 {
1276 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1277
1278 HWND hwnd;
1279 DWORD r;
1280
1281 LVITEM item0;
1282 LVITEM item1;
1283 LVITEM item2;
1284 static CHAR item0text[] = "item0";
1285 static CHAR item1text[] = "item1";
1286 static CHAR item2text[] = "item2";
1287
1288 hwnd = create_listview_control(0);
1289 ok(hwnd != NULL, "failed to create a listview window\n");
1290
1291 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1292
1293 trace("test item count\n");
1294
1295 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1296 expect(0, r);
1297
1298 /* [item0] */
1299 item0.mask = LVIF_TEXT;
1300 item0.iItem = 0;
1301 item0.iSubItem = 0;
1302 item0.pszText = item0text;
1303 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1304 expect(0, r);
1305
1306 /* [item0, item1] */
1307 item1.mask = LVIF_TEXT;
1308 item1.iItem = 1;
1309 item1.iSubItem = 0;
1310 item1.pszText = item1text;
1311 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1312 expect(1, r);
1313
1314 /* [item0, item1, item2] */
1315 item2.mask = LVIF_TEXT;
1316 item2.iItem = 2;
1317 item2.iSubItem = 0;
1318 item2.pszText = item2text;
1319 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1320 expect(2, r);
1321
1322 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1323 expect(3, r);
1324
1325 /* [item0, item1] */
1326 r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0);
1327 expect(TRUE, r);
1328
1329 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1330 expect(2, r);
1331
1332 /* [] */
1333 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1334 expect(TRUE, r);
1335
1336 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1337 expect(0, r);
1338
1339 /* [item0] */
1340 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1341 expect(0, r);
1342
1343 /* [item0, item1] */
1344 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1345 expect(1, r);
1346
1347 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1348 expect(2, r);
1349
1350 /* [item0, item1, item2] */
1351 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1352 expect(2, r);
1353
1354 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1355 expect(3, r);
1356
1357 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
1358
1359 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1360 DestroyWindow(hwnd);
1361 }
1362
1363 static void test_item_position(void)
1364 {
1365 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1366
1367 HWND hwnd;
1368 DWORD r;
1369 POINT position;
1370
1371 LVITEM item0;
1372 LVITEM item1;
1373 LVITEM item2;
1374 static CHAR item0text[] = "item0";
1375 static CHAR item1text[] = "item1";
1376 static CHAR item2text[] = "item2";
1377
1378 hwnd = create_custom_listview_control(LVS_ICON);
1379 ok(hwnd != NULL, "failed to create a listview window\n");
1380
1381 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1382
1383 trace("test item position\n");
1384
1385 /* [item0] */
1386 item0.mask = LVIF_TEXT;
1387 item0.iItem = 0;
1388 item0.iSubItem = 0;
1389 item0.pszText = item0text;
1390 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1391 expect(0, r);
1392
1393 /* [item0, item1] */
1394 item1.mask = LVIF_TEXT;
1395 item1.iItem = 1;
1396 item1.iSubItem = 0;
1397 item1.pszText = item1text;
1398 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1399 expect(1, r);
1400
1401 /* [item0, item1, item2] */
1402 item2.mask = LVIF_TEXT;
1403 item2.iItem = 2;
1404 item2.iSubItem = 0;
1405 item2.pszText = item2text;
1406 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1407 expect(2, r);
1408
1409 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
1410 expect(TRUE, r);
1411 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
1412 expect(TRUE, r);
1413 expect2(10, 5, position.x, position.y);
1414
1415 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
1416 expect(TRUE, r);
1417 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
1418 expect(TRUE, r);
1419 expect2(0, 0, position.x, position.y);
1420
1421 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
1422 expect(TRUE, r);
1423 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
1424 expect(TRUE, r);
1425 expect2(20, 20, position.x, position.y);
1426
1427 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
1428
1429 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1430 DestroyWindow(hwnd);
1431 }
1432
1433 static void test_getorigin(void)
1434 {
1435 /* LVM_GETORIGIN */
1436
1437 HWND hwnd;
1438 DWORD r;
1439 POINT position;
1440
1441 position.x = position.y = 0;
1442
1443 hwnd = create_custom_listview_control(LVS_ICON);
1444 ok(hwnd != NULL, "failed to create a listview window\n");
1445 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1446 trace("test get origin results\n");
1447 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1448 expect(TRUE, r);
1449 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1450 DestroyWindow(hwnd);
1451
1452 hwnd = create_custom_listview_control(LVS_SMALLICON);
1453 ok(hwnd != NULL, "failed to create a listview window\n");
1454 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1455 trace("test get origin results\n");
1456 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1457 expect(TRUE, r);
1458 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1459 DestroyWindow(hwnd);
1460
1461 hwnd = create_custom_listview_control(LVS_LIST);
1462 ok(hwnd != NULL, "failed to create a listview window\n");
1463 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1464 trace("test get origin results\n");
1465 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1466 expect(FALSE, r);
1467 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1468 DestroyWindow(hwnd);
1469
1470 hwnd = create_custom_listview_control(LVS_REPORT);
1471 ok(hwnd != NULL, "failed to create a listview window\n");
1472 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1473 trace("test get origin results\n");
1474 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1475 expect(FALSE, r);
1476 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1477 DestroyWindow(hwnd);
1478
1479 }
1480
1481 static void test_multiselect(void)
1482 {
1483 typedef struct t_select_task
1484 {
1485 const char *descr;
1486 int initPos;
1487 int loopVK;
1488 int count;
1489 int result;
1490 } select_task;
1491
1492 HWND hwnd;
1493 DWORD r;
1494 int i,j,item_count,selected_count;
1495 static const int items=5;
1496 BYTE kstate[256];
1497 select_task task;
1498 LONG_PTR style;
1499
1500 static struct t_select_task task_list[] = {
1501 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
1502 { "using VK_UP", -1, VK_UP, -1, -1 },
1503 { "using VK_END", 0, VK_END, 1, -1 },
1504 { "using VK_HOME", -1, VK_HOME, 1, -1 }
1505 };
1506
1507
1508 hwnd = create_listview_control(0);
1509
1510 for (i=0;i<items;i++) {
1511 insert_item(hwnd, 0);
1512 }
1513
1514 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1515
1516 expect(items,item_count);
1517
1518 for (i=0;i<4;i++) {
1519 task = task_list[i];
1520
1521 /* deselect all items */
1522 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1523 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1524
1525 /* set initial position */
1526 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
1527 ListView_SetItemState(hwnd,(task.initPos == -1 ? item_count -1 : task.initPos),LVIS_SELECTED ,LVIS_SELECTED);
1528
1529 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1530
1531 ok(selected_count == 1, "There should be only one selected item at the beginning (is %d)\n",selected_count);
1532
1533 /* Set SHIFT key pressed */
1534 GetKeyboardState(kstate);
1535 kstate[VK_SHIFT]=0x80;
1536 SetKeyboardState(kstate);
1537
1538 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
1539 r = SendMessage(hwnd, WM_KEYDOWN, task.loopVK, 0);
1540 expect(0,r);
1541 r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
1542 expect(0,r);
1543 }
1544
1545 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1546
1547 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);
1548
1549 /* Set SHIFT key released */
1550 GetKeyboardState(kstate);
1551 kstate[VK_SHIFT]=0x00;
1552 SetKeyboardState(kstate);
1553 }
1554 DestroyWindow(hwnd);
1555
1556 /* make multiple selection, then switch to LVS_SINGLESEL */
1557 hwnd = create_listview_control(0);
1558 for (i=0;i<items;i++) {
1559 insert_item(hwnd, 0);
1560 }
1561 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1562 expect(items,item_count);
1563 /* deselect all items */
1564 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1565 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1566 for (i=0;i<3;i++) {
1567 ListView_SetItemState(hwnd, i, LVIS_SELECTED, LVIS_SELECTED);
1568 }
1569
1570 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1571 expect(3, r);
1572 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1573 todo_wine
1574 expect(-1, r);
1575
1576 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1577 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
1578 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
1579 /* check that style is accepted */
1580 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1581 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
1582
1583 for (i=0;i<3;i++) {
1584 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
1585 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
1586 }
1587 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1588 expect(3, r);
1589 SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1590 expect(3, r);
1591
1592 /* select one more */
1593 ListView_SetItemState(hwnd, 3, LVIS_SELECTED, LVIS_SELECTED);
1594
1595 for (i=0;i<3;i++) {
1596 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
1597 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
1598 }
1599 r = ListView_GetItemState(hwnd, 3, LVIS_SELECTED);
1600 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
1601
1602 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1603 expect(1, r);
1604 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1605 todo_wine
1606 expect(-1, r);
1607
1608 DestroyWindow(hwnd);
1609 }
1610
1611 static void test_subitem_rect(void)
1612 {
1613 HWND hwnd;
1614 DWORD r;
1615 LVCOLUMN col;
1616 RECT rect;
1617
1618 /* test LVM_GETSUBITEMRECT for header */
1619 hwnd = create_listview_control(0);
1620 ok(hwnd != NULL, "failed to create a listview window\n");
1621 /* add some columns */
1622 memset(&col, 0, sizeof(LVCOLUMN));
1623 col.mask = LVCF_WIDTH;
1624 col.cx = 100;
1625 r = -1;
1626 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1627 expect(0, r);
1628 col.cx = 150;
1629 r = -1;
1630 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
1631 expect(1, r);
1632 col.cx = 200;
1633 r = -1;
1634 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
1635 expect(2, r);
1636 /* item = -1 means header, subitem index is 1 based */
1637 rect.left = LVIR_BOUNDS;
1638 rect.top = 0;
1639 rect.right = rect.bottom = 0;
1640 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1641 expect(0, r);
1642
1643 rect.left = LVIR_BOUNDS;
1644 rect.top = 1;
1645 rect.right = rect.bottom = 0;
1646 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1647
1648 ok(r != 0, "Expected not-null LRESULT\n");
1649 expect(100, rect.left);
1650 expect(250, rect.right);
1651 todo_wine
1652 expect(3, rect.top);
1653
1654 rect.left = LVIR_BOUNDS;
1655 rect.top = 2;
1656 rect.right = rect.bottom = 0;
1657 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1658
1659 ok(r != 0, "Expected not-null LRESULT\n");
1660 expect(250, rect.left);
1661 expect(450, rect.right);
1662 todo_wine
1663 expect(3, rect.top);
1664
1665 DestroyWindow(hwnd);
1666
1667 /* try it for non LVS_REPORT style */
1668 hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
1669 GetModuleHandle(NULL), 0);
1670 rect.left = LVIR_BOUNDS;
1671 rect.top = 1;
1672 rect.right = rect.bottom = -10;
1673 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1674 ok(r == 0, "Expected not-null LRESULT\n");
1675 /* rect is unchanged */
1676 expect(0, rect.left);
1677 expect(-10, rect.right);
1678 expect(1, rect.top);
1679 expect(-10, rect.bottom);
1680 DestroyWindow(hwnd);
1681 }
1682
1683 /* comparison callback for test_sorting */
1684 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
1685 {
1686 if (first == second) return 0;
1687 return (first > second ? 1 : -1);
1688 }
1689
1690 static void test_sorting(void)
1691 {
1692 HWND hwnd;
1693 LVITEMA item = {0};
1694 DWORD r;
1695 LONG_PTR style;
1696 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
1697 CHAR buff[10];
1698
1699 hwnd = create_listview_control(0);
1700 ok(hwnd != NULL, "failed to create a listview window\n");
1701
1702 /* insert some items */
1703 item.mask = LVIF_PARAM | LVIF_STATE;
1704 item.state = LVIS_SELECTED;
1705 item.iItem = 0;
1706 item.iSubItem = 0;
1707 item.lParam = 3;
1708 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1709 expect(0, r);
1710
1711 item.mask = LVIF_PARAM;
1712 item.iItem = 1;
1713 item.iSubItem = 0;
1714 item.lParam = 2;
1715 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1716 expect(1, r);
1717
1718 item.mask = LVIF_STATE | LVIF_PARAM;
1719 item.state = LVIS_SELECTED;
1720 item.iItem = 2;
1721 item.iSubItem = 0;
1722 item.lParam = 4;
1723 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1724 expect(2, r);
1725
1726 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1727 expect(-1, r);
1728
1729 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1730 expect(2, r);
1731
1732 r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
1733 expect(TRUE, r);
1734
1735 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1736 expect(2, r);
1737 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1738 expect(-1, r);
1739 r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
1740 expect(0, r);
1741 r = SendMessage(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
1742 expect(LVIS_SELECTED, r);
1743 r = SendMessage(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
1744 expect(LVIS_SELECTED, r);
1745
1746 DestroyWindow(hwnd);
1747
1748 /* switch to LVS_SORTASCENDING when some items added */
1749 hwnd = create_listview_control(0);
1750 ok(hwnd != NULL, "failed to create a listview window\n");
1751
1752 item.mask = LVIF_TEXT;
1753 item.iItem = 0;
1754 item.iSubItem = 0;
1755 item.pszText = names[1];
1756 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1757 expect(0, r);
1758
1759 item.mask = LVIF_TEXT;
1760 item.iItem = 1;
1761 item.iSubItem = 0;
1762 item.pszText = names[2];
1763 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1764 expect(1, r);
1765
1766 item.mask = LVIF_TEXT;
1767 item.iItem = 2;
1768 item.iSubItem = 0;
1769 item.pszText = names[0];
1770 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1771 expect(2, r);
1772
1773 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1774 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
1775 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1776 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
1777
1778 /* no sorting performed when switched to LVS_SORTASCENDING */
1779 item.mask = LVIF_TEXT;
1780 item.iItem = 0;
1781 item.pszText = buff;
1782 item.cchTextMax = sizeof(buff);
1783 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1784 expect(TRUE, r);
1785 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
1786
1787 item.iItem = 1;
1788 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1789 expect(TRUE, r);
1790 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
1791
1792 item.iItem = 2;
1793 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1794 expect(TRUE, r);
1795 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
1796
1797 /* adding new item doesn't resort list */
1798 item.mask = LVIF_TEXT;
1799 item.iItem = 3;
1800 item.iSubItem = 0;
1801 item.pszText = names[3];
1802 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1803 expect(3, r);
1804
1805 item.mask = LVIF_TEXT;
1806 item.iItem = 0;
1807 item.pszText = buff;
1808 item.cchTextMax = sizeof(buff);
1809 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1810 expect(TRUE, r);
1811 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
1812
1813 item.iItem = 1;
1814 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1815 expect(TRUE, r);
1816 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
1817
1818 item.iItem = 2;
1819 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1820 expect(TRUE, r);
1821 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
1822
1823 item.iItem = 3;
1824 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1825 expect(TRUE, r);
1826 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
1827
1828 /* corner case - item should be placed at first position */
1829 item.mask = LVIF_TEXT;
1830 item.iItem = 4;
1831 item.iSubItem = 0;
1832 item.pszText = names[4];
1833 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
1834 expect(0, r);
1835
1836 item.iItem = 0;
1837 item.pszText = buff;
1838 item.cchTextMax = sizeof(buff);
1839 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1840 expect(TRUE, r);
1841 ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
1842
1843 item.iItem = 1;
1844 item.pszText = buff;
1845 item.cchTextMax = sizeof(buff);
1846 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1847 expect(TRUE, r);
1848 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
1849
1850 item.iItem = 2;
1851 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1852 expect(TRUE, r);
1853 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
1854
1855 item.iItem = 3;
1856 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1857 expect(TRUE, r);
1858 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
1859
1860 item.iItem = 4;
1861 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1862 expect(TRUE, r);
1863 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
1864
1865 DestroyWindow(hwnd);
1866 }
1867
1868 static void test_ownerdata(void)
1869 {
1870 HWND hwnd;
1871 LONG_PTR style, ret;
1872 DWORD res;
1873 LVITEMA item;
1874
1875 /* it isn't possible to set LVS_OWNERDATA after creation */
1876 hwnd = create_listview_control(0);
1877 ok(hwnd != NULL, "failed to create a listview window\n");
1878 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1879 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
1880
1881 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1882
1883 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
1884 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
1885 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
1886 "try to switch to LVS_OWNERDATA seq", FALSE);
1887
1888 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1889 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
1890 DestroyWindow(hwnd);
1891
1892 /* try to set LVS_OWNERDATA after creation just having it */
1893 hwnd = create_listview_control(LVS_OWNERDATA);
1894 ok(hwnd != NULL, "failed to create a listview window\n");
1895 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1896 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
1897
1898 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1899
1900 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
1901 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
1902 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
1903 "try to switch to LVS_OWNERDATA seq", FALSE);
1904 DestroyWindow(hwnd);
1905
1906 /* try to remove LVS_OWNERDATA after creation just having it */
1907 hwnd = create_listview_control(LVS_OWNERDATA);
1908 ok(hwnd != NULL, "failed to create a listview window\n");
1909 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1910 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
1911
1912 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1913
1914 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
1915 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
1916 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
1917 "try to switch to LVS_OWNERDATA seq", FALSE);
1918 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1919 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
1920 DestroyWindow(hwnd);
1921
1922 /* try select an item */
1923 hwnd = create_listview_control(LVS_OWNERDATA);
1924 ok(hwnd != NULL, "failed to create a listview window\n");
1925 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
1926 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1927 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1928 expect(0, res);
1929 memset(&item, 0, sizeof(item));
1930 item.stateMask = LVIS_SELECTED;
1931 item.state = LVIS_SELECTED;
1932 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
1933 expect(TRUE, res);
1934 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1935 expect(1, res);
1936 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
1937 expect(1, res);
1938 DestroyWindow(hwnd);
1939
1940 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
1941 hwnd = create_listview_control(LVS_OWNERDATA);
1942 ok(hwnd != NULL, "failed to create a listview window\n");
1943 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
1944 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
1945 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
1946 expect(1, res);
1947 memset(&item, 0, sizeof(item));
1948 item.mask = LVIF_STATE;
1949 item.iItem = 0;
1950 item.stateMask = LVIS_SELECTED;
1951 item.state = LVIS_SELECTED;
1952 res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
1953 expect(FALSE, res);
1954 DestroyWindow(hwnd);
1955 }
1956
1957 static void test_norecompute(void)
1958 {
1959 static CHAR testA[] = "test";
1960 CHAR buff[10];
1961 LVITEMA item;
1962 HWND hwnd;
1963 DWORD res;
1964
1965 /* self containing control */
1966 hwnd = create_listview_control(0);
1967 ok(hwnd != NULL, "failed to create a listview window\n");
1968 memset(&item, 0, sizeof(item));
1969 item.mask = LVIF_TEXT | LVIF_STATE;
1970 item.iItem = 0;
1971 item.stateMask = LVIS_SELECTED;
1972 item.state = LVIS_SELECTED;
1973 item.pszText = testA;
1974 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
1975 expect(0, res);
1976 /* retrieve with LVIF_NORECOMPUTE */
1977 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
1978 item.iItem = 0;
1979 item.pszText = buff;
1980 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
1981 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
1982 expect(TRUE, res);
1983 ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
1984
1985 item.mask = LVIF_TEXT;
1986 item.iItem = 1;
1987 item.pszText = LPSTR_TEXTCALLBACK;
1988 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
1989 expect(1, res);
1990
1991 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
1992 item.iItem = 1;
1993 item.pszText = buff;
1994 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
1995
1996 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1997 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
1998 expect(TRUE, res);
1999 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2000 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2001 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
2002
2003 DestroyWindow(hwnd);
2004
2005 /* LVS_OWNERDATA */
2006 hwnd = create_listview_control(LVS_OWNERDATA);
2007 ok(hwnd != NULL, "failed to create a listview window\n");
2008
2009 item.mask = LVIF_STATE;
2010 item.stateMask = LVIS_SELECTED;
2011 item.state = LVIS_SELECTED;
2012 item.iItem = 0;
2013 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2014 expect(0, res);
2015
2016 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2017 item.iItem = 0;
2018 item.pszText = buff;
2019 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2020 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2021 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2022 expect(TRUE, res);
2023 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2024 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2025 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
2026
2027 DestroyWindow(hwnd);
2028 }
2029
2030 static void test_nosortheader(void)
2031 {
2032 HWND hwnd, header;
2033 LONG_PTR style;
2034
2035 hwnd = create_listview_control(0);
2036 ok(hwnd != NULL, "failed to create a listview window\n");
2037
2038 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
2039 ok(IsWindow(header), "header expected\n");
2040
2041 style = GetWindowLongPtr(header, GWL_STYLE);
2042 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
2043
2044 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2045 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
2046 /* HDS_BUTTONS retained */
2047 style = GetWindowLongPtr(header, GWL_STYLE);
2048 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
2049
2050 DestroyWindow(hwnd);
2051
2052 /* create with LVS_NOSORTHEADER */
2053 hwnd = create_listview_control(LVS_NOSORTHEADER);
2054 ok(hwnd != NULL, "failed to create a listview window\n");
2055
2056 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
2057 ok(IsWindow(header), "header expected\n");
2058
2059 style = GetWindowLongPtr(header, GWL_STYLE);
2060 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
2061
2062 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2063 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
2064 /* not changed here */
2065 style = GetWindowLongPtr(header, GWL_STYLE);
2066 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
2067
2068 DestroyWindow(hwnd);
2069 }
2070
2071 START_TEST(listview)
2072 {
2073 HMODULE hComctl32;
2074 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
2075
2076 hComctl32 = GetModuleHandleA("comctl32.dll");
2077 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
2078 if (pInitCommonControlsEx)
2079 {
2080 INITCOMMONCONTROLSEX iccex;
2081 iccex.dwSize = sizeof(iccex);
2082 iccex.dwICC = ICC_LISTVIEW_CLASSES;
2083 pInitCommonControlsEx(&iccex);
2084 }
2085 else
2086 InitCommonControls();
2087
2088 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2089
2090 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2091 hwndparent = create_parent_window();
2092 ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent window", TRUE);
2093 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2094
2095 test_images();
2096 test_checkboxes();
2097 test_items();
2098 test_create();
2099 test_redraw();
2100 test_customdraw();
2101 test_icon_spacing();
2102 test_color();
2103 test_item_count();
2104 test_item_position();
2105 test_columns();
2106 test_getorigin();
2107 test_multiselect();
2108 test_subitem_rect();
2109 test_sorting();
2110 test_ownerdata();
2111 test_norecompute();
2112 test_nosortheader();
2113 }