push 149f0a5527ac85057a8ef03858d34d91c36f97e8
[wine/hacks.git] / dlls / comctl32 / tests / listview.c
blob8017521c957cd9d523df383a6df7aa8f581dddbb
1 /*
2 * ListView tests
4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * Copyright 2009 Nikolay Sivov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdio.h>
24 #include <windows.h>
25 #include <commctrl.h>
27 #include "wine/test.h"
28 #include "v6util.h"
29 #include "msg.h"
31 #define PARENT_SEQ_INDEX 0
32 #define PARENT_FULL_SEQ_INDEX 1
33 #define LISTVIEW_SEQ_INDEX 2
34 #define EDITBOX_SEQ_INDEX 3
35 #define NUM_MSG_SEQUENCES 4
37 #define LISTVIEW_ID 0
38 #define HEADER_ID 1
40 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
41 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
42 "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
44 static const WCHAR testparentclassW[] =
45 {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
47 HWND hwndparent, hwndparentW;
48 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
49 static BOOL blockEdit;
50 /* return nonzero on NM_HOVER */
51 static BOOL g_block_hover;
52 /* dumps LVN_ITEMCHANGED message data */
53 static BOOL g_dump_itemchanged;
54 /* format reported to control:
55 -1 falls to defproc, anything else returned */
56 INT notifyFormat;
57 /* indicates we're running < 5.80 version */
58 BOOL g_is_below_5;
60 static HWND subclass_editbox(HWND hwndListview);
62 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
64 static const struct message create_ownerdrawfixed_parent_seq[] = {
65 { WM_NOTIFYFORMAT, sent },
66 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
67 { WM_MEASUREITEM, sent },
68 { WM_PARENTNOTIFY, sent },
69 { 0 }
72 static const struct message redraw_listview_seq[] = {
73 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
74 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
75 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
76 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
77 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
78 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
79 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
80 { 0 }
83 static const struct message listview_icon_spacing_seq[] = {
84 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
85 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
86 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
87 { 0 }
90 static const struct message listview_color_seq[] = {
91 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
92 { LVM_GETBKCOLOR, sent },
93 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
94 { LVM_GETTEXTCOLOR, sent },
95 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
96 { LVM_GETTEXTBKCOLOR, sent },
98 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
99 { LVM_GETBKCOLOR, sent },
100 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
101 { LVM_GETTEXTCOLOR, sent },
102 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
103 { LVM_GETTEXTBKCOLOR, sent },
105 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
106 { LVM_GETBKCOLOR, sent },
107 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
108 { LVM_GETTEXTCOLOR, sent },
109 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
110 { LVM_GETTEXTBKCOLOR, sent },
112 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
113 { LVM_GETBKCOLOR, sent },
114 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
115 { LVM_GETTEXTCOLOR, sent },
116 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
117 { LVM_GETTEXTBKCOLOR, sent },
118 { 0 }
121 static const struct message listview_item_count_seq[] = {
122 { LVM_GETITEMCOUNT, sent },
123 { LVM_INSERTITEM, sent },
124 { LVM_INSERTITEM, sent },
125 { LVM_INSERTITEM, sent },
126 { LVM_GETITEMCOUNT, sent },
127 { LVM_DELETEITEM, sent|wparam, 2 },
128 { WM_NCPAINT, sent|optional },
129 { WM_ERASEBKGND, sent|optional },
130 { LVM_GETITEMCOUNT, sent },
131 { LVM_DELETEALLITEMS, sent },
132 { LVM_GETITEMCOUNT, sent },
133 { LVM_INSERTITEM, sent },
134 { LVM_INSERTITEM, sent },
135 { LVM_GETITEMCOUNT, sent },
136 { LVM_INSERTITEM, sent },
137 { LVM_GETITEMCOUNT, sent },
138 { 0 }
141 static const struct message listview_itempos_seq[] = {
142 { LVM_INSERTITEM, sent },
143 { LVM_INSERTITEM, sent },
144 { LVM_INSERTITEM, sent },
145 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
146 { WM_NCPAINT, sent|optional },
147 { WM_ERASEBKGND, sent|optional },
148 { LVM_GETITEMPOSITION, sent|wparam, 1 },
149 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
150 { LVM_GETITEMPOSITION, sent|wparam, 2 },
151 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
152 { LVM_GETITEMPOSITION, sent|wparam, 0 },
153 { 0 }
156 static const struct message listview_ownerdata_switchto_seq[] = {
157 { WM_STYLECHANGING, sent },
158 { WM_STYLECHANGED, sent },
159 { 0 }
162 static const struct message listview_getorderarray_seq[] = {
163 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
164 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
165 { 0 }
168 static const struct message empty_seq[] = {
169 { 0 }
172 static const struct message forward_erasebkgnd_parent_seq[] = {
173 { WM_ERASEBKGND, sent },
174 { 0 }
177 static const struct message ownderdata_select_focus_parent_seq[] = {
178 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
179 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
180 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
181 { 0 }
184 static const struct message ownerdata_setstate_all_parent_seq[] = {
185 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
186 { 0 }
189 static const struct message ownerdata_defocus_all_parent_seq[] = {
190 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
191 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
192 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
193 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
194 { 0 }
197 static const struct message ownerdata_deselect_all_parent_seq[] = {
198 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
199 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
200 { 0 }
203 static const struct message select_all_parent_seq[] = {
204 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
205 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
207 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
208 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
210 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
211 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
213 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
214 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
216 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
217 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
218 { 0 }
221 static const struct message textcallback_set_again_parent_seq[] = {
222 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
223 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
224 { 0 }
227 static const struct message single_getdispinfo_parent_seq[] = {
228 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
229 { 0 }
232 static const struct message getitemposition_seq1[] = {
233 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
234 { 0 }
237 static const struct message getitemposition_seq2[] = {
238 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
239 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
240 { 0 }
243 static const struct message editbox_create_pos[] = {
244 /* sequence sent after LVN_BEGINLABELEDIT */
245 /* next two are 4.7x specific */
246 { WM_WINDOWPOSCHANGING, sent },
247 { WM_WINDOWPOSCHANGED, sent|optional },
249 { WM_WINDOWPOSCHANGING, sent|optional },
250 { WM_NCCALCSIZE, sent },
251 { WM_WINDOWPOSCHANGED, sent },
252 { WM_MOVE, sent|defwinproc },
253 { WM_SIZE, sent|defwinproc },
254 /* the rest is todo, skipped in 4.7x */
255 { WM_WINDOWPOSCHANGING, sent|optional },
256 { WM_WINDOWPOSCHANGED, sent|optional },
257 { 0 }
260 static const struct message scroll_parent_seq[] = {
261 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
262 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
263 { 0 }
266 static const struct message setredraw_seq[] = {
267 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
268 { 0 }
271 static const struct message lvs_ex_transparentbkgnd_seq[] = {
272 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
273 { 0 }
276 static const struct message edit_end_nochange[] = {
277 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
278 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
279 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
280 { 0 }
283 static const struct message hover_parent[] = {
284 { WM_GETDLGCODE, sent }, /* todo_wine */
285 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
286 { 0 }
289 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
291 static LONG defwndproc_counter = 0;
292 LRESULT ret;
293 struct message msg;
295 msg.message = message;
296 msg.flags = sent|wparam|lparam;
297 if (defwndproc_counter) msg.flags |= defwinproc;
298 msg.wParam = wParam;
299 msg.lParam = lParam;
300 if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
302 /* log system messages, except for painting */
303 if (message < WM_USER &&
304 message != WM_PAINT &&
305 message != WM_ERASEBKGND &&
306 message != WM_NCPAINT &&
307 message != WM_NCHITTEST &&
308 message != WM_GETTEXT &&
309 message != WM_GETICON &&
310 message != WM_DEVICECHANGE)
312 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
314 add_message(sequences, PARENT_SEQ_INDEX, &msg);
316 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
318 switch (message)
320 case WM_NOTIFY:
322 switch (((NMHDR*)lParam)->code)
324 case LVN_BEGINLABELEDIT:
325 /* subclass edit box */
326 if (!blockEdit)
327 subclass_editbox(((NMHDR*)lParam)->hwndFrom);
329 return blockEdit;
331 case LVN_ENDLABELEDIT:
333 /* always accept new item text */
334 NMLVDISPINFO *di = (NMLVDISPINFO*)lParam;
335 trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText);
336 return TRUE;
338 case LVN_BEGINSCROLL:
339 case LVN_ENDSCROLL:
341 NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
343 trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
344 "BEGIN" : "END", pScroll->dx, pScroll->dy);
346 break;
347 case LVN_ITEMCHANGED:
348 if (g_dump_itemchanged)
350 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
351 trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
352 nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
354 break;
355 case NM_HOVER:
356 if (g_block_hover) return 1;
357 break;
359 break;
361 case WM_NOTIFYFORMAT:
363 /* force to return format */
364 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
365 break;
369 defwndproc_counter++;
370 ret = DefWindowProcA(hwnd, message, wParam, lParam);
371 defwndproc_counter--;
373 return ret;
376 static BOOL register_parent_wnd_class(BOOL Unicode)
378 WNDCLASSA clsA;
379 WNDCLASSW clsW;
381 if (Unicode)
383 clsW.style = 0;
384 clsW.lpfnWndProc = parent_wnd_proc;
385 clsW.cbClsExtra = 0;
386 clsW.cbWndExtra = 0;
387 clsW.hInstance = GetModuleHandleW(NULL);
388 clsW.hIcon = 0;
389 clsW.hCursor = LoadCursorA(0, IDC_ARROW);
390 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
391 clsW.lpszMenuName = NULL;
392 clsW.lpszClassName = testparentclassW;
394 else
396 clsA.style = 0;
397 clsA.lpfnWndProc = parent_wnd_proc;
398 clsA.cbClsExtra = 0;
399 clsA.cbWndExtra = 0;
400 clsA.hInstance = GetModuleHandleA(NULL);
401 clsA.hIcon = 0;
402 clsA.hCursor = LoadCursorA(0, IDC_ARROW);
403 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
404 clsA.lpszMenuName = NULL;
405 clsA.lpszClassName = "Listview test parent class";
408 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
411 static HWND create_parent_window(BOOL Unicode)
413 static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W'};
414 HWND hwnd;
416 if (!register_parent_wnd_class(Unicode))
417 return NULL;
419 blockEdit = FALSE;
420 notifyFormat = -1;
422 if (Unicode)
423 hwnd = CreateWindowExW(0, testparentclassW, nameW,
424 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
425 WS_MAXIMIZEBOX | WS_VISIBLE,
426 0, 0, 100, 100,
427 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
428 else
429 hwnd = CreateWindowExA(0, "Listview test parent class",
430 "Listview test parent window",
431 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
432 WS_MAXIMIZEBOX | WS_VISIBLE,
433 0, 0, 100, 100,
434 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
435 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
436 return hwnd;
439 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
441 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
442 static LONG defwndproc_counter = 0;
443 LRESULT ret;
444 struct message msg;
446 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
448 /* some debug output for style changing */
449 if ((message == WM_STYLECHANGING ||
450 message == WM_STYLECHANGED) && lParam)
452 STYLESTRUCT *style = (STYLESTRUCT*)lParam;
453 trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
456 msg.message = message;
457 msg.flags = sent|wparam|lparam;
458 if (defwndproc_counter) msg.flags |= defwinproc;
459 msg.wParam = wParam;
460 msg.lParam = lParam;
461 msg.id = LISTVIEW_ID;
462 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
464 defwndproc_counter++;
465 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
466 defwndproc_counter--;
467 return ret;
470 static HWND create_listview_control(DWORD style)
472 WNDPROC oldproc;
473 HWND hwnd;
474 RECT rect;
476 GetClientRect(hwndparent, &rect);
477 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
478 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
479 0, 0, rect.right, rect.bottom,
480 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
481 ok(hwnd != NULL, "gle=%d\n", GetLastError());
483 if (!hwnd) return NULL;
485 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
486 (LONG_PTR)listview_subclass_proc);
487 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
489 return hwnd;
492 /* unicode listview window with specified parent */
493 static HWND create_listview_controlW(DWORD style, HWND parent)
495 WNDPROC oldproc;
496 HWND hwnd;
497 RECT rect;
498 static const WCHAR nameW[] = {'f','o','o',0};
500 GetClientRect(parent, &rect);
501 hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
502 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
503 0, 0, rect.right, rect.bottom,
504 parent, NULL, GetModuleHandleW(NULL), NULL);
505 ok(hwnd != NULL, "gle=%d\n", GetLastError());
507 if (!hwnd) return NULL;
509 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
510 (LONG_PTR)listview_subclass_proc);
511 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
513 return hwnd;
516 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
518 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
519 static LONG defwndproc_counter = 0;
520 LRESULT ret;
521 struct message msg;
523 trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
525 msg.message = message;
526 msg.flags = sent|wparam|lparam;
527 if (defwndproc_counter) msg.flags |= defwinproc;
528 msg.wParam = wParam;
529 msg.lParam = lParam;
530 msg.id = HEADER_ID;
531 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
533 defwndproc_counter++;
534 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
535 defwndproc_counter--;
536 return ret;
539 static HWND subclass_header(HWND hwndListview)
541 WNDPROC oldproc;
542 HWND hwnd;
544 hwnd = ListView_GetHeader(hwndListview);
545 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
546 (LONG_PTR)header_subclass_proc);
547 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
549 return hwnd;
552 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
554 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
555 static LONG defwndproc_counter = 0;
556 LRESULT ret;
557 struct message msg;
559 msg.message = message;
560 msg.flags = sent|wparam|lparam;
561 if (defwndproc_counter) msg.flags |= defwinproc;
562 msg.wParam = wParam;
563 msg.lParam = lParam;
565 /* all we need is sizing */
566 if (message == WM_WINDOWPOSCHANGING ||
567 message == WM_NCCALCSIZE ||
568 message == WM_WINDOWPOSCHANGED ||
569 message == WM_MOVE ||
570 message == WM_SIZE)
572 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
575 defwndproc_counter++;
576 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
577 defwndproc_counter--;
578 return ret;
581 static HWND subclass_editbox(HWND hwndListview)
583 WNDPROC oldproc;
584 HWND hwnd;
586 hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0);
587 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
588 (LONG_PTR)editbox_subclass_proc);
589 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
591 return hwnd;
594 /* Performs a single LVM_HITTEST test */
595 static void test_lvm_hittest(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
596 BOOL todo_item, BOOL todo_flags, int line)
598 LVHITTESTINFO lpht;
599 DWORD ret;
601 lpht.pt.x = x;
602 lpht.pt.y = y;
603 lpht.iSubItem = 10;
605 trace("hittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
606 ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
608 if (todo_item)
610 todo_wine
612 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
613 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
614 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
617 else
619 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
620 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
621 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
624 if (todo_flags)
626 todo_wine
627 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
629 else if (broken_flags)
630 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
631 "Expected flags %x, got %x\n", flags, lpht.flags);
632 else
633 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
636 /* Performs a single LVM_SUBITEMHITTEST test */
637 static void test_lvm_subitemhittest(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
638 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
640 LVHITTESTINFO lpht;
641 DWORD ret;
643 lpht.pt.x = x;
644 lpht.pt.y = y;
646 trace("subhittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
647 ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
649 if (todo_item)
651 todo_wine
653 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
654 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
657 else
659 ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
660 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
663 if (todo_subitem)
665 todo_wine
666 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
668 else
669 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
671 if (todo_flags)
673 todo_wine
674 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
676 else
677 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
680 static void test_images(void)
682 HWND hwnd;
683 DWORD r;
684 LVITEM item;
685 HIMAGELIST himl;
686 HBITMAP hbmp;
687 RECT r1, r2;
688 static CHAR hello[] = "hello";
690 himl = ImageList_Create(40, 40, 0, 4, 4);
691 ok(himl != NULL, "failed to create imagelist\n");
693 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
694 ok(hbmp != NULL, "failed to create bitmap\n");
696 r = ImageList_Add(himl, hbmp, 0);
697 ok(r == 0, "should be zero\n");
699 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
700 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
701 ok(hwnd != NULL, "failed to create listview window\n");
703 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
704 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
706 ok(r == 0, "should return zero\n");
708 r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
709 ok(r == 0, "should return zero\n");
711 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
712 /* returns dimensions */
714 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
715 ok(r == 0, "should be zero items\n");
717 item.mask = LVIF_IMAGE | LVIF_TEXT;
718 item.iItem = 0;
719 item.iSubItem = 1;
720 item.iImage = 0;
721 item.pszText = 0;
722 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
723 ok(r == -1, "should fail\n");
725 item.iSubItem = 0;
726 item.pszText = hello;
727 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
728 ok(r == 0, "should not fail\n");
730 memset(&r1, 0, sizeof r1);
731 r1.left = LVIR_ICON;
732 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
734 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
735 ok(r == TRUE, "should not fail\n");
737 item.iSubItem = 0;
738 item.pszText = hello;
739 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
740 ok(r == 0, "should not fail\n");
742 memset(&r2, 0, sizeof r2);
743 r2.left = LVIR_ICON;
744 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
746 ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
748 DestroyWindow(hwnd);
751 static void test_checkboxes(void)
753 HWND hwnd;
754 LVITEMA item;
755 DWORD r;
756 static CHAR text[] = "Text",
757 text2[] = "Text2",
758 text3[] = "Text3";
760 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
761 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
762 ok(hwnd != NULL, "failed to create listview window\n");
764 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
765 item.mask = LVIF_TEXT | LVIF_STATE;
766 item.stateMask = 0xffff;
767 item.state = 0xfccc;
768 item.iItem = 0;
769 item.iSubItem = 0;
770 item.pszText = text;
771 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
772 ok(r == 0, "ret %d\n", r);
774 item.iItem = 0;
775 item.mask = LVIF_STATE;
776 item.stateMask = 0xffff;
777 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
778 ok(item.state == 0xfccc, "state %x\n", item.state);
780 /* Don't set LVIF_STATE */
781 item.mask = LVIF_TEXT;
782 item.stateMask = 0xffff;
783 item.state = 0xfccc;
784 item.iItem = 1;
785 item.iSubItem = 0;
786 item.pszText = text;
787 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
788 ok(r == 1, "ret %d\n", r);
790 item.iItem = 1;
791 item.mask = LVIF_STATE;
792 item.stateMask = 0xffff;
793 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
794 ok(item.state == 0, "state %x\n", item.state);
796 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
797 ok(r == 0, "should return zero\n");
799 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
800 item.iItem = 0;
801 item.mask = LVIF_STATE;
802 item.stateMask = 0xffff;
803 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
804 if (item.state != 0x1ccc)
806 win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
807 DestroyWindow(hwnd);
808 return;
811 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
812 item.iItem = 2;
813 item.mask = LVIF_TEXT;
814 item.state = 0;
815 item.pszText = text2;
816 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
817 ok(r == 2, "ret %d\n", r);
819 item.iItem = 2;
820 item.mask = LVIF_STATE;
821 item.stateMask = 0xffff;
822 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
823 ok(item.state == 0x1000, "state %x\n", item.state);
825 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
826 item.iItem = 3;
827 item.mask = LVIF_TEXT | LVIF_STATE;
828 item.stateMask = 0xffff;
829 item.state = 0x2aaa;
830 item.pszText = text3;
831 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
832 ok(r == 3, "ret %d\n", r);
834 item.iItem = 3;
835 item.mask = LVIF_STATE;
836 item.stateMask = 0xffff;
837 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
838 ok(item.state == 0x1aaa, "state %x\n", item.state);
840 /* Set an item's state to checked */
841 item.iItem = 3;
842 item.mask = LVIF_STATE;
843 item.stateMask = 0xf000;
844 item.state = 0x2000;
845 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
847 item.iItem = 3;
848 item.mask = LVIF_STATE;
849 item.stateMask = 0xffff;
850 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
851 ok(item.state == 0x2aaa, "state %x\n", item.state);
853 /* Check that only the bits we asked for are returned,
854 * and that all the others are set to zero
856 item.iItem = 3;
857 item.mask = LVIF_STATE;
858 item.stateMask = 0xf000;
859 item.state = 0xffff;
860 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
861 ok(item.state == 0x2000, "state %x\n", item.state);
863 /* Set the style again and check that doesn't change an item's state */
864 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
865 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
867 item.iItem = 3;
868 item.mask = LVIF_STATE;
869 item.stateMask = 0xffff;
870 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
871 ok(item.state == 0x2aaa, "state %x\n", item.state);
873 /* Unsetting the checkbox extended style doesn't change an item's state */
874 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
875 ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
877 item.iItem = 3;
878 item.mask = LVIF_STATE;
879 item.stateMask = 0xffff;
880 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
881 ok(item.state == 0x2aaa, "state %x\n", item.state);
883 /* Now setting the style again will change an item's state */
884 r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
885 ok(r == 0, "ret %x\n", r);
887 item.iItem = 3;
888 item.mask = LVIF_STATE;
889 item.stateMask = 0xffff;
890 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
891 ok(item.state == 0x1aaa, "state %x\n", item.state);
893 /* Toggle checkbox tests (bug 9934) */
894 memset (&item, 0xcc, sizeof(item));
895 item.mask = LVIF_STATE;
896 item.iItem = 3;
897 item.iSubItem = 0;
898 item.state = LVIS_FOCUSED;
899 item.stateMask = LVIS_FOCUSED;
900 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
901 expect(1, r);
903 item.iItem = 3;
904 item.mask = LVIF_STATE;
905 item.stateMask = 0xffff;
906 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
907 ok(item.state == 0x1aab, "state %x\n", item.state);
909 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
910 expect(0, r);
911 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
912 expect(0, r);
914 item.iItem = 3;
915 item.mask = LVIF_STATE;
916 item.stateMask = 0xffff;
917 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
918 ok(item.state == 0x2aab, "state %x\n", item.state);
920 r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
921 expect(0, r);
922 r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
923 expect(0, r);
925 item.iItem = 3;
926 item.mask = LVIF_STATE;
927 item.stateMask = 0xffff;
928 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
929 ok(item.state == 0x1aab, "state %x\n", item.state);
931 DestroyWindow(hwnd);
934 static void insert_column(HWND hwnd, int idx)
936 LVCOLUMN column;
937 DWORD rc;
939 memset(&column, 0xcc, sizeof(column));
940 column.mask = LVCF_SUBITEM;
941 column.iSubItem = idx;
943 rc = ListView_InsertColumn(hwnd, idx, &column);
944 expect(idx, rc);
947 static void insert_item(HWND hwnd, int idx)
949 static CHAR text[] = "foo";
951 LVITEMA item;
952 DWORD rc;
954 memset(&item, 0xcc, sizeof (item));
955 item.mask = LVIF_TEXT;
956 item.iItem = idx;
957 item.iSubItem = 0;
958 item.pszText = text;
960 rc = ListView_InsertItem(hwnd, &item);
961 expect(idx, rc);
964 static void test_items(void)
966 const LPARAM lparamTest = 0x42;
967 HWND hwnd;
968 LVITEMA item;
969 DWORD r;
970 static CHAR text[] = "Text";
972 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
973 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
974 ok(hwnd != NULL, "failed to create listview window\n");
977 * Test setting/getting item params
980 /* Set up two columns */
981 insert_column(hwnd, 0);
982 insert_column(hwnd, 1);
984 /* LVIS_SELECTED with zero stateMask */
985 /* set */
986 memset (&item, 0, sizeof (item));
987 item.mask = LVIF_STATE;
988 item.state = LVIS_SELECTED;
989 item.stateMask = 0;
990 item.iItem = 0;
991 item.iSubItem = 0;
992 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
993 ok(r == 0, "ret %d\n", r);
994 /* get */
995 memset (&item, 0xcc, sizeof (item));
996 item.mask = LVIF_STATE;
997 item.stateMask = LVIS_SELECTED;
998 item.state = 0;
999 item.iItem = 0;
1000 item.iSubItem = 0;
1001 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1002 ok(r != 0, "ret %d\n", r);
1003 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1004 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1006 /* LVIS_SELECTED with zero stateMask */
1007 /* set */
1008 memset (&item, 0, sizeof (item));
1009 item.mask = LVIF_STATE;
1010 item.state = LVIS_FOCUSED;
1011 item.stateMask = 0;
1012 item.iItem = 0;
1013 item.iSubItem = 0;
1014 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1015 ok(r == 0, "ret %d\n", r);
1016 /* get */
1017 memset (&item, 0xcc, sizeof (item));
1018 item.mask = LVIF_STATE;
1019 item.stateMask = LVIS_FOCUSED;
1020 item.state = 0;
1021 item.iItem = 0;
1022 item.iSubItem = 0;
1023 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1024 ok(r != 0, "ret %d\n", r);
1025 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1026 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1028 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1029 /* set */
1030 memset (&item, 0, sizeof (item));
1031 item.mask = LVIF_STATE;
1032 item.state = LVIS_CUT;
1033 item.stateMask = LVIS_FOCUSED;
1034 item.iItem = 0;
1035 item.iSubItem = 0;
1036 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1037 ok(r == 0, "ret %d\n", r);
1038 /* get */
1039 memset (&item, 0xcc, sizeof (item));
1040 item.mask = LVIF_STATE;
1041 item.stateMask = LVIS_CUT;
1042 item.state = 0;
1043 item.iItem = 0;
1044 item.iSubItem = 0;
1045 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1046 ok(r != 0, "ret %d\n", r);
1047 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1048 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
1050 /* Insert an item with just a param */
1051 memset (&item, 0xcc, sizeof (item));
1052 item.mask = LVIF_PARAM;
1053 item.iItem = 0;
1054 item.iSubItem = 0;
1055 item.lParam = lparamTest;
1056 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1057 ok(r == 0, "ret %d\n", r);
1059 /* Test getting of the param */
1060 memset (&item, 0xcc, sizeof (item));
1061 item.mask = LVIF_PARAM;
1062 item.iItem = 0;
1063 item.iSubItem = 0;
1064 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1065 ok(r != 0, "ret %d\n", r);
1066 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1068 /* Set up a subitem */
1069 memset (&item, 0xcc, sizeof (item));
1070 item.mask = LVIF_TEXT;
1071 item.iItem = 0;
1072 item.iSubItem = 1;
1073 item.pszText = text;
1074 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1075 ok(r != 0, "ret %d\n", r);
1077 /* Query param from subitem: returns main item param */
1078 memset (&item, 0xcc, sizeof (item));
1079 item.mask = LVIF_PARAM;
1080 item.iItem = 0;
1081 item.iSubItem = 1;
1082 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1083 ok(r != 0, "ret %d\n", r);
1084 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1086 /* Set up param on first subitem: no effect */
1087 memset (&item, 0xcc, sizeof (item));
1088 item.mask = LVIF_PARAM;
1089 item.iItem = 0;
1090 item.iSubItem = 1;
1091 item.lParam = lparamTest+1;
1092 r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1093 ok(r == 0, "ret %d\n", r);
1095 /* Query param from subitem again: should still return main item param */
1096 memset (&item, 0xcc, sizeof (item));
1097 item.mask = LVIF_PARAM;
1098 item.iItem = 0;
1099 item.iSubItem = 1;
1100 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1101 ok(r != 0, "ret %d\n", r);
1102 ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1104 /**** Some tests of state highlighting ****/
1105 memset (&item, 0xcc, sizeof (item));
1106 item.mask = LVIF_STATE;
1107 item.iItem = 0;
1108 item.iSubItem = 0;
1109 item.state = LVIS_SELECTED;
1110 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1111 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1112 ok(r != 0, "ret %d\n", r);
1113 item.iSubItem = 1;
1114 item.state = LVIS_DROPHILITED;
1115 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
1116 ok(r != 0, "ret %d\n", r);
1118 memset (&item, 0xcc, sizeof (item));
1119 item.mask = LVIF_STATE;
1120 item.iItem = 0;
1121 item.iSubItem = 0;
1122 item.stateMask = -1;
1123 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1124 ok(r != 0, "ret %d\n", r);
1125 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1126 item.iSubItem = 1;
1127 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
1128 ok(r != 0, "ret %d\n", r);
1129 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1131 /* some notnull but meaningless masks */
1132 memset (&item, 0, sizeof(item));
1133 item.mask = LVIF_NORECOMPUTE;
1134 item.iItem = 0;
1135 item.iSubItem = 0;
1136 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1137 ok(r != 0, "ret %d\n", r);
1138 memset (&item, 0, sizeof(item));
1139 item.mask = LVIF_DI_SETITEM;
1140 item.iItem = 0;
1141 item.iSubItem = 0;
1142 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1143 ok(r != 0, "ret %d\n", r);
1145 /* set text to callback value already having it */
1146 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1147 expect(TRUE, r);
1148 memset (&item, 0, sizeof (item));
1149 item.mask = LVIF_TEXT;
1150 item.pszText = LPSTR_TEXTCALLBACK;
1151 item.iItem = 0;
1152 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1153 ok(r == 0, "ret %d\n", r);
1154 memset (&item, 0, sizeof (item));
1156 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1158 item.pszText = LPSTR_TEXTCALLBACK;
1159 r = SendMessage(hwnd, LVM_SETITEMTEXT, 0 , (LPARAM) &item);
1160 expect(TRUE, r);
1162 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1163 "check callback text comparison rule", FALSE);
1165 DestroyWindow(hwnd);
1168 static void test_columns(void)
1170 HWND hwnd, hwndheader;
1171 LVCOLUMN column;
1172 DWORD rc;
1173 INT order[2];
1175 hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
1176 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1177 ok(hwnd != NULL, "failed to create listview window\n");
1179 /* Add a column with no mask */
1180 memset(&column, 0xcc, sizeof(column));
1181 column.mask = 0;
1182 rc = ListView_InsertColumn(hwnd, 0, &column);
1183 ok(rc==0, "Inserting column with no mask failed with %d\n", rc);
1185 /* Check its width */
1186 rc = ListView_GetColumnWidth(hwnd, 0);
1187 ok(rc==10 ||
1188 broken(rc==0), /* win9x */
1189 "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1191 DestroyWindow(hwnd);
1193 /* LVM_GETCOLUMNORDERARRAY */
1194 hwnd = create_listview_control(LVS_REPORT);
1195 hwndheader = subclass_header(hwnd);
1197 memset(&column, 0, sizeof(column));
1198 column.mask = LVCF_WIDTH;
1199 column.cx = 100;
1200 rc = ListView_InsertColumn(hwnd, 0, &column);
1201 ok(rc == 0, "Inserting column failed with %d\n", rc);
1203 column.cx = 200;
1204 rc = ListView_InsertColumn(hwnd, 1, &column);
1205 ok(rc == 1, "Inserting column failed with %d\n", rc);
1207 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1209 rc = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1210 ok(rc != 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n");
1211 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1212 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1214 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1216 DestroyWindow(hwnd);
1218 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1219 static WNDPROC listviewWndProc;
1220 static HIMAGELIST test_create_imagelist;
1222 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1224 LRESULT ret;
1226 if (uMsg == WM_CREATE)
1228 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
1229 lpcs->style |= LVS_REPORT;
1231 ret = CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam);
1232 if (uMsg == WM_CREATE) SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1233 return ret;
1236 static void test_create(void)
1238 HWND hList;
1239 HWND hHeader;
1240 LONG_PTR ret;
1241 LONG r;
1242 LVCOLUMNA col;
1243 RECT rect;
1244 WNDCLASSEX cls;
1245 DWORD style;
1247 cls.cbSize = sizeof(WNDCLASSEX);
1248 ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n");
1249 listviewWndProc = cls.lpfnWndProc;
1250 cls.lpfnWndProc = create_test_wndproc;
1251 cls.lpszClassName = "MyListView32";
1252 ok(RegisterClassEx(&cls), "RegisterClassEx failed\n");
1254 test_create_imagelist = ImageList_Create(16, 16, 0, 5, 10);
1255 hList = CreateWindow("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1256 ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1257 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1259 if (!IsWindow(hHeader))
1261 /* version 4.0 */
1262 win_skip("LVM_GETHEADER not implemented. Skipping.\n");
1263 DestroyWindow(hList);
1264 return;
1267 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1268 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1269 DestroyWindow(hList);
1271 /* header isn't created on LVS_ICON and LVS_LIST styles */
1272 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1273 GetModuleHandle(NULL), 0);
1274 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1275 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1276 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1277 /* insert column */
1278 memset(&col, 0, sizeof(LVCOLUMNA));
1279 col.mask = LVCF_WIDTH;
1280 col.cx = 100;
1281 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1282 ok(r == 0, "Expected 0 column's inserted\n");
1283 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1284 ok(IsWindow(hHeader), "Header should be created\n");
1285 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1286 style = GetWindowLong(hHeader, GWL_STYLE);
1287 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1288 DestroyWindow(hList);
1290 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1291 GetModuleHandle(NULL), 0);
1292 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1293 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1294 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1295 /* insert column */
1296 memset(&col, 0, sizeof(LVCOLUMNA));
1297 col.mask = LVCF_WIDTH;
1298 col.cx = 100;
1299 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1300 ok(r == 0, "Expected 0 column's inserted\n");
1301 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1302 ok(IsWindow(hHeader), "Header should be created\n");
1303 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1304 DestroyWindow(hList);
1306 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1307 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1308 GetModuleHandle(NULL), 0);
1309 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLongPtr(hList, GWL_STYLE) | LVS_REPORT);
1310 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1311 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1312 ok(IsWindow(hHeader), "Header should be created\n");
1313 ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLong(hList, GWL_STYLE) & ~LVS_REPORT);
1314 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1315 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1316 ok(IsWindow(hHeader), "Header should be created\n");
1317 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1318 DestroyWindow(hList);
1320 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1321 hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1322 GetModuleHandle(NULL), 0);
1323 ret = SetWindowLongPtr(hList, GWL_STYLE,
1324 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1325 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1326 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1327 ok(IsWindow(hHeader), "Header should be created\n");
1328 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1329 ret = SetWindowLongPtr(hList, GWL_STYLE,
1330 (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1331 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1332 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1333 ok(IsWindow(hHeader), "Header should be created\n");
1334 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1335 DestroyWindow(hList);
1337 /* LVS_REPORT without WS_VISIBLE */
1338 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1339 GetModuleHandle(NULL), 0);
1340 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1341 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1342 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1343 /* insert column */
1344 memset(&col, 0, sizeof(LVCOLUMNA));
1345 col.mask = LVCF_WIDTH;
1346 col.cx = 100;
1347 r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
1348 ok(r == 0, "Expected 0 column's inserted\n");
1349 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1350 ok(IsWindow(hHeader), "Header should be created\n");
1351 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1352 DestroyWindow(hList);
1354 /* LVS_REPORT without WS_VISIBLE, try to show it */
1355 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1356 GetModuleHandle(NULL), 0);
1357 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1358 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1359 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1360 ShowWindow(hList, SW_SHOW);
1361 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1362 ok(IsWindow(hHeader), "Header should be created\n");
1363 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1364 DestroyWindow(hList);
1366 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1367 hList = CreateWindow("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1368 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0);
1369 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1370 ok(IsWindow(hHeader), "Header should be created\n");
1371 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1372 /* HDS_DRAGDROP set by default */
1373 ok(GetWindowLongPtr(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1374 DestroyWindow(hList);
1376 /* setting LVS_EX_HEADERDRAGDROP creates header */
1377 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1378 GetModuleHandle(NULL), 0);
1379 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1380 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1381 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1382 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1383 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1384 ok(IsWindow(hHeader) ||
1385 broken(!IsWindow(hHeader)), /* 4.7x common controls */
1386 "Header should be created\n");
1387 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1388 DestroyWindow(hList);
1390 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1391 hList = create_listview_control(LVS_ICON);
1392 SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1393 r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1394 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1395 DestroyWindow(hList);
1397 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1398 hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1399 GetModuleHandle(NULL), 0);
1400 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1401 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1403 rect.left = LVIR_BOUNDS;
1404 rect.top = 1;
1405 rect.right = rect.bottom = -10;
1406 r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1407 ok(r != 0, "Expected not-null LRESULT\n");
1409 hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0);
1410 ok(!IsWindow(hHeader), "Header shouldn't be created\n");
1411 ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n");
1413 DestroyWindow(hList);
1415 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1416 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1417 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1418 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1419 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1420 DestroyWindow(hList);
1423 static void test_redraw(void)
1425 HWND hwnd, hwndheader;
1426 HDC hdc;
1427 BOOL res;
1428 DWORD r;
1430 hwnd = create_listview_control(LVS_REPORT);
1431 hwndheader = subclass_header(hwnd);
1433 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1435 trace("invalidate & update\n");
1436 InvalidateRect(hwnd, NULL, TRUE);
1437 UpdateWindow(hwnd);
1438 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1440 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1442 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1443 /* 1. Without backbuffer */
1444 res = ListView_SetBkColor(hwnd, CLR_NONE);
1445 expect(TRUE, res);
1447 hdc = GetWindowDC(hwndparent);
1449 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1450 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1451 ok(r != 0, "Expected not zero result\n");
1452 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1453 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1455 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1456 expect(TRUE, res);
1458 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1459 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1460 ok(r != 0, "Expected not zero result\n");
1461 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1462 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1464 /* 2. With backbuffer */
1465 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1466 LVS_EX_DOUBLEBUFFER);
1467 res = ListView_SetBkColor(hwnd, CLR_NONE);
1468 expect(TRUE, res);
1470 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1471 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1472 ok(r != 0, "Expected not zero result\n");
1473 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1474 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1476 res = ListView_SetBkColor(hwnd, CLR_DEFAULT);
1477 expect(TRUE, res);
1479 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1480 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1481 todo_wine ok(r != 0, "Expected not zero result\n");
1482 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1483 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1485 ReleaseDC(hwndparent, hdc);
1487 DestroyWindow(hwnd);
1490 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1492 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1494 if(msg == WM_NOTIFY) {
1495 NMHDR *nmhdr = (PVOID)lp;
1496 if(nmhdr->code == NM_CUSTOMDRAW) {
1497 NMLVCUSTOMDRAW *nmlvcd = (PVOID)nmhdr;
1498 trace("NMCUSTOMDRAW (0x%.8x)\n", nmlvcd->nmcd.dwDrawStage);
1499 switch(nmlvcd->nmcd.dwDrawStage) {
1500 case CDDS_PREPAINT:
1501 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1502 return CDRF_NOTIFYITEMDRAW;
1503 case CDDS_ITEMPREPAINT:
1504 nmlvcd->clrTextBk = CLR_DEFAULT;
1505 return CDRF_NOTIFYSUBITEMDRAW;
1506 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
1507 clr = GetBkColor(nmlvcd->nmcd.hdc);
1508 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1509 return CDRF_NOTIFYPOSTPAINT;
1510 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
1511 clr = GetBkColor(nmlvcd->nmcd.hdc);
1512 todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1513 return CDRF_DODEFAULT;
1515 return CDRF_DODEFAULT;
1519 return DefWindowProcA(hwnd, msg, wp, lp);
1522 static void test_customdraw(void)
1524 HWND hwnd;
1525 WNDPROC oldwndproc;
1527 hwnd = create_listview_control(LVS_REPORT);
1529 insert_column(hwnd, 0);
1530 insert_column(hwnd, 1);
1531 insert_item(hwnd, 0);
1533 oldwndproc = (WNDPROC)SetWindowLongPtr(hwndparent, GWLP_WNDPROC,
1534 (LONG_PTR)cd_wndproc);
1536 InvalidateRect(hwnd, NULL, TRUE);
1537 UpdateWindow(hwnd);
1539 SetWindowLongPtr(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
1541 DestroyWindow(hwnd);
1544 static void test_icon_spacing(void)
1546 /* LVM_SETICONSPACING */
1547 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1549 HWND hwnd;
1550 WORD w, h;
1551 DWORD r;
1553 hwnd = create_listview_control(LVS_ICON);
1554 ok(hwnd != NULL, "failed to create a listview window\n");
1556 r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY);
1557 expect(NFR_ANSI, r);
1559 /* reset the icon spacing to defaults */
1560 SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1562 /* now we can request what the defaults are */
1563 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
1564 w = LOWORD(r);
1565 h = HIWORD(r);
1567 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1569 trace("test icon spacing\n");
1571 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
1572 ok(r == MAKELONG(w, h) ||
1573 broken(r == MAKELONG(w, w)), /* win98 */
1574 "Expected %d, got %d\n", MAKELONG(w, h), r);
1576 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
1577 if (r == 0)
1579 /* version 4.0 */
1580 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
1581 DestroyWindow(hwnd);
1582 return;
1584 expect(MAKELONG(20,30), r);
1586 r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
1587 expect(MAKELONG(25,35), r);
1589 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
1591 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1592 DestroyWindow(hwnd);
1595 static void test_color(void)
1597 /* SETBKCOLOR/GETBKCOLOR, SETTEXTCOLOR/GETTEXTCOLOR, SETTEXTBKCOLOR/GETTEXTBKCOLOR */
1599 HWND hwnd;
1600 DWORD r;
1601 int i;
1603 COLORREF color;
1604 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
1606 hwnd = create_listview_control(LVS_REPORT);
1607 ok(hwnd != NULL, "failed to create a listview window\n");
1609 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1611 trace("test color seq\n");
1612 for (i = 0; i < 4; i++)
1614 color = colors[i];
1616 r = SendMessage(hwnd, LVM_SETBKCOLOR, 0, color);
1617 expect(TRUE, r);
1618 r = SendMessage(hwnd, LVM_GETBKCOLOR, 0, color);
1619 expect(color, r);
1621 r = SendMessage(hwnd, LVM_SETTEXTCOLOR, 0, color);
1622 expect (TRUE, r);
1623 r = SendMessage(hwnd, LVM_GETTEXTCOLOR, 0, color);
1624 expect(color, r);
1626 r = SendMessage(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
1627 expect(TRUE, r);
1628 r = SendMessage(hwnd, LVM_GETTEXTBKCOLOR, 0, color);
1629 expect(color, r);
1632 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
1634 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1635 DestroyWindow(hwnd);
1638 static void test_item_count(void)
1640 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
1642 HWND hwnd;
1643 DWORD r;
1644 HDC hdc;
1645 HFONT hOldFont;
1646 TEXTMETRICA tm;
1647 RECT rect;
1648 INT height;
1650 LVITEM item0;
1651 LVITEM item1;
1652 LVITEM item2;
1653 static CHAR item0text[] = "item0";
1654 static CHAR item1text[] = "item1";
1655 static CHAR item2text[] = "item2";
1657 hwnd = create_listview_control(LVS_REPORT);
1658 ok(hwnd != NULL, "failed to create a listview window\n");
1660 /* resize in dpiaware manner to fit all 3 items added */
1661 hdc = GetDC(0);
1662 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
1663 GetTextMetricsA(hdc, &tm);
1664 /* 2 extra pixels for bounds and header border */
1665 height = tm.tmHeight + 2;
1666 SelectObject(hdc, hOldFont);
1667 ReleaseDC(0, hdc);
1669 GetWindowRect(hwnd, &rect);
1670 /* 3 items + 1 header + 1 to be sure */
1671 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
1673 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1675 trace("test item count\n");
1677 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1678 expect(0, r);
1680 /* [item0] */
1681 item0.mask = LVIF_TEXT;
1682 item0.iItem = 0;
1683 item0.iSubItem = 0;
1684 item0.pszText = item0text;
1685 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1686 expect(0, r);
1688 /* [item0, item1] */
1689 item1.mask = LVIF_TEXT;
1690 item1.iItem = 1;
1691 item1.iSubItem = 0;
1692 item1.pszText = item1text;
1693 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1694 expect(1, r);
1696 /* [item0, item1, item2] */
1697 item2.mask = LVIF_TEXT;
1698 item2.iItem = 2;
1699 item2.iSubItem = 0;
1700 item2.pszText = item2text;
1701 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1702 expect(2, r);
1704 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1705 expect(3, r);
1707 /* [item0, item1] */
1708 r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0);
1709 expect(TRUE, r);
1711 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1712 expect(2, r);
1714 /* [] */
1715 r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
1716 expect(TRUE, r);
1718 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1719 expect(0, r);
1721 /* [item0] */
1722 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1723 expect(0, r);
1725 /* [item0, item1] */
1726 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1727 expect(1, r);
1729 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1730 expect(2, r);
1732 /* [item0, item1, item2] */
1733 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1734 expect(2, r);
1736 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1737 expect(3, r);
1739 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
1741 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1742 DestroyWindow(hwnd);
1745 static void test_item_position(void)
1747 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
1749 HWND hwnd;
1750 DWORD r;
1751 POINT position;
1753 LVITEM item0;
1754 LVITEM item1;
1755 LVITEM item2;
1756 static CHAR item0text[] = "item0";
1757 static CHAR item1text[] = "item1";
1758 static CHAR item2text[] = "item2";
1760 hwnd = create_listview_control(LVS_ICON);
1761 ok(hwnd != NULL, "failed to create a listview window\n");
1763 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1765 trace("test item position\n");
1767 /* [item0] */
1768 item0.mask = LVIF_TEXT;
1769 item0.iItem = 0;
1770 item0.iSubItem = 0;
1771 item0.pszText = item0text;
1772 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item0);
1773 expect(0, r);
1775 /* [item0, item1] */
1776 item1.mask = LVIF_TEXT;
1777 item1.iItem = 1;
1778 item1.iSubItem = 0;
1779 item1.pszText = item1text;
1780 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item1);
1781 expect(1, r);
1783 /* [item0, item1, item2] */
1784 item2.mask = LVIF_TEXT;
1785 item2.iItem = 2;
1786 item2.iSubItem = 0;
1787 item2.pszText = item2text;
1788 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item2);
1789 expect(2, r);
1791 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
1792 expect(TRUE, r);
1793 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
1794 expect(TRUE, r);
1795 expect2(10, 5, position.x, position.y);
1797 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
1798 expect(TRUE, r);
1799 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
1800 expect(TRUE, r);
1801 expect2(0, 0, position.x, position.y);
1803 r = SendMessage(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
1804 expect(TRUE, r);
1805 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
1806 expect(TRUE, r);
1807 expect2(20, 20, position.x, position.y);
1809 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
1811 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1812 DestroyWindow(hwnd);
1815 static void test_getorigin(void)
1817 /* LVM_GETORIGIN */
1819 HWND hwnd;
1820 DWORD r;
1821 POINT position;
1823 position.x = position.y = 0;
1825 hwnd = create_listview_control(LVS_ICON);
1826 ok(hwnd != NULL, "failed to create a listview window\n");
1827 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1828 trace("test get origin results\n");
1829 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1830 expect(TRUE, r);
1831 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1832 DestroyWindow(hwnd);
1834 hwnd = create_listview_control(LVS_SMALLICON);
1835 ok(hwnd != NULL, "failed to create a listview window\n");
1836 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1837 trace("test get origin results\n");
1838 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1839 expect(TRUE, r);
1840 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1841 DestroyWindow(hwnd);
1843 hwnd = create_listview_control(LVS_LIST);
1844 ok(hwnd != NULL, "failed to create a listview window\n");
1845 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1846 trace("test get origin results\n");
1847 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1848 expect(FALSE, r);
1849 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1850 DestroyWindow(hwnd);
1852 hwnd = create_listview_control(LVS_REPORT);
1853 ok(hwnd != NULL, "failed to create a listview window\n");
1854 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1855 trace("test get origin results\n");
1856 r = SendMessage(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
1857 expect(FALSE, r);
1858 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1859 DestroyWindow(hwnd);
1863 static void test_multiselect(void)
1865 typedef struct t_select_task
1867 const char *descr;
1868 int initPos;
1869 int loopVK;
1870 int count;
1871 int result;
1872 } select_task;
1874 HWND hwnd;
1875 DWORD r;
1876 int i,j,item_count,selected_count;
1877 static const int items=5;
1878 BYTE kstate[256];
1879 select_task task;
1880 LONG_PTR style;
1881 LVITEMA item;
1883 static struct t_select_task task_list[] = {
1884 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
1885 { "using VK_UP", -1, VK_UP, -1, -1 },
1886 { "using VK_END", 0, VK_END, 1, -1 },
1887 { "using VK_HOME", -1, VK_HOME, 1, -1 }
1891 hwnd = create_listview_control(LVS_REPORT);
1893 for (i=0;i<items;i++) {
1894 insert_item(hwnd, 0);
1897 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1899 expect(items,item_count);
1901 for (i=0;i<4;i++) {
1902 task = task_list[i];
1904 /* deselect all items */
1905 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1906 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1908 /* set initial position */
1909 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
1910 ListView_SetItemState(hwnd,(task.initPos == -1 ? item_count -1 : task.initPos),LVIS_SELECTED ,LVIS_SELECTED);
1912 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1914 ok(selected_count == 1, "There should be only one selected item at the beginning (is %d)\n",selected_count);
1916 /* Set SHIFT key pressed */
1917 GetKeyboardState(kstate);
1918 kstate[VK_SHIFT]=0x80;
1919 SetKeyboardState(kstate);
1921 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
1922 r = SendMessage(hwnd, WM_KEYDOWN, task.loopVK, 0);
1923 expect(0,r);
1924 r = SendMessage(hwnd, WM_KEYUP, task.loopVK, 0);
1925 expect(0,r);
1928 selected_count = (int)SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1930 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);
1932 /* Set SHIFT key released */
1933 GetKeyboardState(kstate);
1934 kstate[VK_SHIFT]=0x00;
1935 SetKeyboardState(kstate);
1937 DestroyWindow(hwnd);
1939 /* make multiple selection, then switch to LVS_SINGLESEL */
1940 hwnd = create_listview_control(LVS_REPORT);
1941 for (i=0;i<items;i++) {
1942 insert_item(hwnd, 0);
1944 item_count = (int)SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
1945 expect(items,item_count);
1947 /* try with NULL pointer */
1948 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)NULL);
1949 expect(FALSE, r);
1951 /* select all, check notifications */
1952 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1954 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1956 item.stateMask = LVIS_SELECTED;
1957 item.state = LVIS_SELECTED;
1958 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
1959 expect(TRUE, r);
1961 ok_sequence(sequences, PARENT_SEQ_INDEX, select_all_parent_seq,
1962 "select all notification", FALSE);
1964 /* deselect all items */
1965 ListView_SetItemState(hwnd, -1, 0, LVIS_SELECTED);
1966 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
1967 for (i=0;i<3;i++) {
1968 ListView_SetItemState(hwnd, i, LVIS_SELECTED, LVIS_SELECTED);
1971 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1972 expect(3, r);
1973 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1974 expect(-1, r);
1976 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1977 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
1978 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
1979 /* check that style is accepted */
1980 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
1981 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
1983 for (i=0;i<3;i++) {
1984 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
1985 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
1987 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
1988 expect(3, r);
1989 SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
1990 expect(3, r);
1992 /* select one more */
1993 ListView_SetItemState(hwnd, 3, LVIS_SELECTED, LVIS_SELECTED);
1995 for (i=0;i<3;i++) {
1996 r = ListView_GetItemState(hwnd, i, LVIS_SELECTED);
1997 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
1999 r = ListView_GetItemState(hwnd, 3, LVIS_SELECTED);
2000 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2002 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2003 expect(1, r);
2004 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2005 expect(-1, r);
2007 /* try to select all on LVS_SINGLESEL */
2008 memset(&item, 0, sizeof(item));
2009 item.stateMask = LVIS_SELECTED;
2010 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2011 expect(TRUE, r);
2012 SendMessage(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2014 item.stateMask = LVIS_SELECTED;
2015 item.state = LVIS_SELECTED;
2016 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2017 expect(FALSE, r);
2019 r = ListView_GetSelectedCount(hwnd);
2020 expect(0, r);
2021 r = ListView_GetSelectionMark(hwnd);
2022 expect(-1, r);
2024 /* try to deselect all on LVS_SINGLESEL */
2025 item.stateMask = LVIS_SELECTED;
2026 item.state = LVIS_SELECTED;
2027 r = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2028 expect(TRUE, r);
2030 item.stateMask = LVIS_SELECTED;
2031 item.state = 0;
2032 r = SendMessage(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2033 expect(TRUE, r);
2034 r = ListView_GetSelectedCount(hwnd);
2035 expect(0, r);
2037 DestroyWindow(hwnd);
2040 static void test_subitem_rect(void)
2042 HWND hwnd;
2043 DWORD r;
2044 LVCOLUMN col;
2045 RECT rect;
2047 /* test LVM_GETSUBITEMRECT for header */
2048 hwnd = create_listview_control(LVS_REPORT);
2049 ok(hwnd != NULL, "failed to create a listview window\n");
2050 /* add some columns */
2051 memset(&col, 0, sizeof(LVCOLUMN));
2052 col.mask = LVCF_WIDTH;
2053 col.cx = 100;
2054 r = -1;
2055 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
2056 expect(0, r);
2057 col.cx = 150;
2058 r = -1;
2059 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 1, (LPARAM)&col);
2060 expect(1, r);
2061 col.cx = 200;
2062 r = -1;
2063 r = SendMessage(hwnd, LVM_INSERTCOLUMN, 2, (LPARAM)&col);
2064 expect(2, r);
2065 /* item = -1 means header, subitem index is 1 based */
2066 rect.left = LVIR_BOUNDS;
2067 rect.top = 0;
2068 rect.right = rect.bottom = 0;
2069 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2070 expect(0, r);
2072 rect.left = LVIR_BOUNDS;
2073 rect.top = 1;
2074 rect.right = rect.bottom = 0;
2075 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2077 ok(r != 0, "Expected not-null LRESULT\n");
2078 expect(100, rect.left);
2079 expect(250, rect.right);
2080 todo_wine
2081 expect(3, rect.top);
2083 rect.left = LVIR_BOUNDS;
2084 rect.top = 2;
2085 rect.right = rect.bottom = 0;
2086 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2088 ok(r != 0, "Expected not-null LRESULT\n");
2089 expect(250, rect.left);
2090 expect(450, rect.right);
2091 todo_wine
2092 expect(3, rect.top);
2094 /* item LVS_REPORT padding isn't applied to subitems */
2095 insert_item(hwnd, 0);
2097 rect.left = LVIR_BOUNDS;
2098 rect.top = 1;
2099 rect.right = rect.bottom = 0;
2100 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2101 ok(r != 0, "Expected not-null LRESULT\n");
2102 expect(100, rect.left);
2103 expect(250, rect.right);
2105 rect.left = LVIR_ICON;
2106 rect.top = 1;
2107 rect.right = rect.bottom = 0;
2108 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2109 ok(r != 0, "Expected not-null LRESULT\n");
2110 /* no icon attached - zero width rectangle, with no left padding */
2111 expect(100, rect.left);
2112 expect(100, rect.right);
2114 rect.left = LVIR_LABEL;
2115 rect.top = 1;
2116 rect.right = rect.bottom = 0;
2117 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2118 ok(r != 0, "Expected not-null LRESULT\n");
2119 /* same as full LVIR_BOUNDS */
2120 expect(100, rect.left);
2121 expect(250, rect.right);
2123 DestroyWindow(hwnd);
2125 /* try it for non LVS_REPORT style */
2126 hwnd = CreateWindow("SysListView32", "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2127 GetModuleHandle(NULL), 0);
2128 rect.left = LVIR_BOUNDS;
2129 rect.top = 1;
2130 rect.right = rect.bottom = -10;
2131 r = SendMessage(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2132 ok(r == 0, "Expected not-null LRESULT\n");
2133 /* rect is unchanged */
2134 expect(0, rect.left);
2135 expect(-10, rect.right);
2136 expect(1, rect.top);
2137 expect(-10, rect.bottom);
2138 DestroyWindow(hwnd);
2141 /* comparison callback for test_sorting */
2142 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
2144 if (first == second) return 0;
2145 return (first > second ? 1 : -1);
2148 static void test_sorting(void)
2150 HWND hwnd;
2151 LVITEMA item = {0};
2152 DWORD r;
2153 LONG_PTR style;
2154 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2155 CHAR buff[10];
2157 hwnd = create_listview_control(LVS_REPORT);
2158 ok(hwnd != NULL, "failed to create a listview window\n");
2160 /* insert some items */
2161 item.mask = LVIF_PARAM | LVIF_STATE;
2162 item.state = LVIS_SELECTED;
2163 item.iItem = 0;
2164 item.iSubItem = 0;
2165 item.lParam = 3;
2166 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2167 expect(0, r);
2169 item.mask = LVIF_PARAM;
2170 item.iItem = 1;
2171 item.iSubItem = 0;
2172 item.lParam = 2;
2173 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2174 expect(1, r);
2176 item.mask = LVIF_STATE | LVIF_PARAM;
2177 item.state = LVIS_SELECTED;
2178 item.iItem = 2;
2179 item.iSubItem = 0;
2180 item.lParam = 4;
2181 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2182 expect(2, r);
2184 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2185 expect(-1, r);
2187 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2188 expect(2, r);
2190 r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
2191 expect(TRUE, r);
2193 r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2194 expect(2, r);
2195 r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2196 expect(-1, r);
2197 r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
2198 expect(0, r);
2199 r = SendMessage(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
2200 expect(LVIS_SELECTED, r);
2201 r = SendMessage(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
2202 expect(LVIS_SELECTED, r);
2204 DestroyWindow(hwnd);
2206 /* switch to LVS_SORTASCENDING when some items added */
2207 hwnd = create_listview_control(LVS_REPORT);
2208 ok(hwnd != NULL, "failed to create a listview window\n");
2210 item.mask = LVIF_TEXT;
2211 item.iItem = 0;
2212 item.iSubItem = 0;
2213 item.pszText = names[1];
2214 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2215 expect(0, r);
2217 item.mask = LVIF_TEXT;
2218 item.iItem = 1;
2219 item.iSubItem = 0;
2220 item.pszText = names[2];
2221 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2222 expect(1, r);
2224 item.mask = LVIF_TEXT;
2225 item.iItem = 2;
2226 item.iSubItem = 0;
2227 item.pszText = names[0];
2228 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2229 expect(2, r);
2231 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2232 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2233 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2234 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2236 /* no sorting performed when switched to LVS_SORTASCENDING */
2237 item.mask = LVIF_TEXT;
2238 item.iItem = 0;
2239 item.pszText = buff;
2240 item.cchTextMax = sizeof(buff);
2241 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2242 expect(TRUE, r);
2243 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2245 item.iItem = 1;
2246 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2247 expect(TRUE, r);
2248 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2250 item.iItem = 2;
2251 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2252 expect(TRUE, r);
2253 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2255 /* adding new item doesn't resort list */
2256 item.mask = LVIF_TEXT;
2257 item.iItem = 3;
2258 item.iSubItem = 0;
2259 item.pszText = names[3];
2260 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2261 expect(3, r);
2263 item.mask = LVIF_TEXT;
2264 item.iItem = 0;
2265 item.pszText = buff;
2266 item.cchTextMax = sizeof(buff);
2267 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2268 expect(TRUE, r);
2269 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2271 item.iItem = 1;
2272 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2273 expect(TRUE, r);
2274 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2276 item.iItem = 2;
2277 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2278 expect(TRUE, r);
2279 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2281 item.iItem = 3;
2282 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2283 expect(TRUE, r);
2284 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2286 /* corner case - item should be placed at first position */
2287 item.mask = LVIF_TEXT;
2288 item.iItem = 4;
2289 item.iSubItem = 0;
2290 item.pszText = names[4];
2291 r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
2292 expect(0, r);
2294 item.iItem = 0;
2295 item.pszText = buff;
2296 item.cchTextMax = sizeof(buff);
2297 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2298 expect(TRUE, r);
2299 ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
2301 item.iItem = 1;
2302 item.pszText = buff;
2303 item.cchTextMax = sizeof(buff);
2304 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2305 expect(TRUE, r);
2306 ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2308 item.iItem = 2;
2309 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2310 expect(TRUE, r);
2311 ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2313 item.iItem = 3;
2314 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2315 expect(TRUE, r);
2316 ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
2318 item.iItem = 4;
2319 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item);
2320 expect(TRUE, r);
2321 ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
2323 DestroyWindow(hwnd);
2326 static void test_ownerdata(void)
2328 HWND hwnd;
2329 LONG_PTR style, ret;
2330 DWORD res;
2331 LVITEMA item;
2333 /* it isn't possible to set LVS_OWNERDATA after creation */
2334 if (g_is_below_5)
2336 win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2338 else
2340 hwnd = create_listview_control(LVS_REPORT);
2341 ok(hwnd != NULL, "failed to create a listview window\n");
2342 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2343 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
2345 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2347 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2348 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2349 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2350 "try to switch to LVS_OWNERDATA seq", FALSE);
2352 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2353 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
2354 DestroyWindow(hwnd);
2357 /* try to set LVS_OWNERDATA after creation just having it */
2358 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2359 ok(hwnd != NULL, "failed to create a listview window\n");
2360 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2361 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2363 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2365 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
2366 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2367 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2368 "try to switch to LVS_OWNERDATA seq", FALSE);
2369 DestroyWindow(hwnd);
2371 /* try to remove LVS_OWNERDATA after creation just having it */
2372 if (g_is_below_5)
2374 win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
2376 else
2378 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2379 ok(hwnd != NULL, "failed to create a listview window\n");
2380 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2381 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2383 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2385 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
2386 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
2387 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
2388 "try to switch to LVS_OWNERDATA seq", FALSE);
2389 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2390 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
2391 DestroyWindow(hwnd);
2394 /* try select an item */
2395 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2396 ok(hwnd != NULL, "failed to create a listview window\n");
2397 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2398 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2399 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2400 expect(0, res);
2401 memset(&item, 0, sizeof(item));
2402 item.stateMask = LVIS_SELECTED;
2403 item.state = LVIS_SELECTED;
2404 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2405 expect(TRUE, res);
2406 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2407 expect(1, res);
2408 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2409 expect(1, res);
2410 DestroyWindow(hwnd);
2412 /* LVM_SETITEM is unsupported on LVS_OWNERDATA */
2413 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2414 ok(hwnd != NULL, "failed to create a listview window\n");
2415 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2416 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2417 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2418 expect(1, res);
2419 memset(&item, 0, sizeof(item));
2420 item.mask = LVIF_STATE;
2421 item.iItem = 0;
2422 item.stateMask = LVIS_SELECTED;
2423 item.state = LVIS_SELECTED;
2424 res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2425 expect(FALSE, res);
2426 DestroyWindow(hwnd);
2428 /* check notifications after focused/selected changed */
2429 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2430 ok(hwnd != NULL, "failed to create a listview window\n");
2431 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
2432 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2434 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2436 memset(&item, 0, sizeof(item));
2437 item.stateMask = LVIS_SELECTED;
2438 item.state = LVIS_SELECTED;
2439 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2440 expect(TRUE, res);
2442 ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
2443 "ownerdata select notification", TRUE);
2445 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2447 memset(&item, 0, sizeof(item));
2448 item.stateMask = LVIS_FOCUSED;
2449 item.state = LVIS_FOCUSED;
2450 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2451 expect(TRUE, res);
2453 ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
2454 "ownerdata focus notification", TRUE);
2456 /* select all, check notifications */
2457 item.stateMask = LVIS_SELECTED;
2458 item.state = 0;
2459 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2460 expect(TRUE, res);
2462 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2464 item.stateMask = LVIS_SELECTED;
2465 item.state = LVIS_SELECTED;
2467 g_dump_itemchanged = TRUE;
2468 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2469 expect(TRUE, res);
2470 g_dump_itemchanged = FALSE;
2472 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2473 "ownerdata select all notification", TRUE);
2475 /* select all again, note that all items are selected already */
2476 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2477 item.stateMask = LVIS_SELECTED;
2478 item.state = LVIS_SELECTED;
2479 g_dump_itemchanged = TRUE;
2480 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2481 expect(TRUE, res);
2482 g_dump_itemchanged = FALSE;
2483 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2484 "ownerdata select all notification", TRUE);
2485 /* deselect all */
2486 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2487 item.stateMask = LVIS_SELECTED;
2488 item.state = 0;
2489 g_dump_itemchanged = TRUE;
2490 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2491 expect(TRUE, res);
2492 g_dump_itemchanged = FALSE;
2493 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
2494 "ownerdata deselect all notification", TRUE);
2496 /* select one, then deselect all */
2497 item.stateMask = LVIS_SELECTED;
2498 item.state = LVIS_SELECTED;
2499 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2500 expect(TRUE, res);
2501 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2502 item.stateMask = LVIS_SELECTED;
2503 item.state = 0;
2504 g_dump_itemchanged = TRUE;
2505 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2506 expect(TRUE, res);
2507 g_dump_itemchanged = FALSE;
2508 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
2509 "ownerdata select all notification", TRUE);
2511 /* remove focused, try to focus all */
2512 item.stateMask = LVIS_FOCUSED;
2513 item.state = LVIS_FOCUSED;
2514 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2515 expect(TRUE, res);
2516 item.stateMask = LVIS_FOCUSED;
2517 item.state = 0;
2518 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2519 expect(TRUE, res);
2520 item.stateMask = LVIS_FOCUSED;
2521 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
2522 expect(0, res);
2523 /* setting all to focused returns failure value */
2524 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2525 item.stateMask = LVIS_FOCUSED;
2526 item.state = LVIS_FOCUSED;
2527 g_dump_itemchanged = TRUE;
2528 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2529 expect(FALSE, res);
2530 g_dump_itemchanged = FALSE;
2531 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2532 "ownerdata focus all notification", FALSE);
2533 /* focus single item, remove all */
2534 item.stateMask = LVIS_FOCUSED;
2535 item.state = LVIS_FOCUSED;
2536 res = SendMessage(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2537 expect(TRUE, res);
2538 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2539 item.stateMask = LVIS_FOCUSED;
2540 item.state = 0;
2541 g_dump_itemchanged = TRUE;
2542 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2543 expect(TRUE, res);
2544 g_dump_itemchanged = FALSE;
2545 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
2546 "ownerdata remove focus all notification", TRUE);
2547 /* set all cut */
2548 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2549 item.stateMask = LVIS_CUT;
2550 item.state = LVIS_CUT;
2551 g_dump_itemchanged = TRUE;
2552 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2553 expect(TRUE, res);
2554 g_dump_itemchanged = FALSE;
2555 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2556 "ownerdata cut all notification", TRUE);
2557 /* all marked cut, try again */
2558 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2559 item.stateMask = LVIS_CUT;
2560 item.state = LVIS_CUT;
2561 g_dump_itemchanged = TRUE;
2562 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2563 expect(TRUE, res);
2564 g_dump_itemchanged = FALSE;
2565 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
2566 "ownerdata cut all notification #2", TRUE);
2568 DestroyWindow(hwnd);
2570 /* check notifications on LVM_GETITEM */
2571 /* zero callback mask */
2572 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2573 ok(hwnd != NULL, "failed to create a listview window\n");
2574 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
2575 ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
2577 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2579 memset(&item, 0, sizeof(item));
2580 item.stateMask = LVIS_SELECTED;
2581 item.mask = LVIF_STATE;
2582 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2583 expect(TRUE, res);
2585 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2586 "ownerdata getitem selected state 1", FALSE);
2588 /* non zero callback mask but not we asking for */
2589 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
2590 expect(TRUE, res);
2592 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2594 memset(&item, 0, sizeof(item));
2595 item.stateMask = LVIS_SELECTED;
2596 item.mask = LVIF_STATE;
2597 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2598 expect(TRUE, res);
2600 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2601 "ownerdata getitem selected state 2", FALSE);
2603 /* LVIS_OVERLAYMASK callback mask, asking for index */
2604 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2606 memset(&item, 0, sizeof(item));
2607 item.stateMask = LVIS_OVERLAYMASK;
2608 item.mask = LVIF_STATE;
2609 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
2610 expect(TRUE, res);
2612 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
2613 "ownerdata getitem selected state 2", FALSE);
2615 DestroyWindow(hwnd);
2617 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
2618 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
2619 ok(hwnd != NULL, "failed to create a listview window\n");
2620 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2621 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2622 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2623 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
2624 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2625 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
2626 DestroyWindow(hwnd);
2627 /* apparently it's allowed to switch these style on after creation */
2628 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2629 ok(hwnd != NULL, "failed to create a listview window\n");
2630 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2631 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2632 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
2633 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2634 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2635 DestroyWindow(hwnd);
2637 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2638 ok(hwnd != NULL, "failed to create a listview window\n");
2639 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2640 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
2641 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
2642 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2643 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
2644 DestroyWindow(hwnd);
2647 static void test_norecompute(void)
2649 static CHAR testA[] = "test";
2650 CHAR buff[10];
2651 LVITEMA item;
2652 HWND hwnd;
2653 DWORD res;
2655 /* self containing control */
2656 hwnd = create_listview_control(LVS_REPORT);
2657 ok(hwnd != NULL, "failed to create a listview window\n");
2658 memset(&item, 0, sizeof(item));
2659 item.mask = LVIF_TEXT | LVIF_STATE;
2660 item.iItem = 0;
2661 item.stateMask = LVIS_SELECTED;
2662 item.state = LVIS_SELECTED;
2663 item.pszText = testA;
2664 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2665 expect(0, res);
2666 /* retrieve with LVIF_NORECOMPUTE */
2667 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2668 item.iItem = 0;
2669 item.pszText = buff;
2670 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2671 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2672 expect(TRUE, res);
2673 ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
2675 item.mask = LVIF_TEXT;
2676 item.iItem = 1;
2677 item.pszText = LPSTR_TEXTCALLBACK;
2678 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2679 expect(1, res);
2681 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2682 item.iItem = 1;
2683 item.pszText = buff;
2684 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2686 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2687 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2688 expect(TRUE, res);
2689 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2690 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2691 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
2693 DestroyWindow(hwnd);
2695 /* LVS_OWNERDATA */
2696 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2697 ok(hwnd != NULL, "failed to create a listview window\n");
2699 item.mask = LVIF_STATE;
2700 item.stateMask = LVIS_SELECTED;
2701 item.state = LVIS_SELECTED;
2702 item.iItem = 0;
2703 res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
2704 expect(0, res);
2706 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
2707 item.iItem = 0;
2708 item.pszText = buff;
2709 item.cchTextMax = sizeof(buff)/sizeof(CHAR);
2710 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2711 res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
2712 expect(TRUE, res);
2713 ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n",
2714 LPSTR_TEXTCALLBACK, (VOID*)item.pszText);
2715 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
2717 DestroyWindow(hwnd);
2720 static void test_nosortheader(void)
2722 HWND hwnd, header;
2723 LONG_PTR style;
2725 hwnd = create_listview_control(LVS_REPORT);
2726 ok(hwnd != NULL, "failed to create a listview window\n");
2728 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
2729 ok(IsWindow(header), "header expected\n");
2731 style = GetWindowLongPtr(header, GWL_STYLE);
2732 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
2734 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2735 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
2736 /* HDS_BUTTONS retained */
2737 style = GetWindowLongPtr(header, GWL_STYLE);
2738 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
2740 DestroyWindow(hwnd);
2742 /* create with LVS_NOSORTHEADER */
2743 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
2744 ok(hwnd != NULL, "failed to create a listview window\n");
2746 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
2747 ok(IsWindow(header), "header expected\n");
2749 style = GetWindowLongPtr(header, GWL_STYLE);
2750 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
2752 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2753 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
2754 /* not changed here */
2755 style = GetWindowLongPtr(header, GWL_STYLE);
2756 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
2758 DestroyWindow(hwnd);
2761 static void test_setredraw(void)
2763 HWND hwnd;
2764 DWORD_PTR style;
2765 DWORD ret;
2766 HDC hdc;
2767 RECT rect;
2769 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
2770 ok(hwnd != NULL, "failed to create a listview window\n");
2772 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
2773 ListView seems to handle it internally without DefWinProc */
2775 /* default value first */
2776 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
2777 expect(0, ret);
2778 /* disable */
2779 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2780 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
2781 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2782 expect(0, ret);
2783 style = GetWindowLongPtr(hwnd, GWL_STYLE);
2784 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
2785 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
2786 expect(0, ret);
2788 /* check update rect after redrawing */
2789 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2790 expect(0, ret);
2791 InvalidateRect(hwnd, NULL, FALSE);
2792 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
2793 rect.right = rect.bottom = 1;
2794 GetUpdateRect(hwnd, &rect, FALSE);
2795 expect(0, rect.right);
2796 expect(0, rect.bottom);
2798 /* WM_ERASEBKGND */
2799 hdc = GetWindowDC(hwndparent);
2800 ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
2801 expect(TRUE, ret);
2802 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2803 expect(0, ret);
2804 ret = SendMessage(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
2805 expect(TRUE, ret);
2806 ret = SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
2807 expect(0, ret);
2808 ReleaseDC(hwndparent, hdc);
2810 /* check notification messages to show that repainting is disabled */
2811 ret = SendMessage(hwnd, LVM_SETITEMCOUNT, 1, 0);
2812 expect(TRUE, ret);
2813 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2814 expect(0, ret);
2815 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2817 InvalidateRect(hwnd, NULL, TRUE);
2818 UpdateWindow(hwnd);
2819 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2820 "redraw after WM_SETREDRAW (FALSE)", FALSE);
2822 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
2823 expect(TRUE, ret);
2824 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2825 InvalidateRect(hwnd, NULL, TRUE);
2826 UpdateWindow(hwnd);
2827 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
2828 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
2830 /* message isn't forwarded to header */
2831 subclass_header(hwnd);
2832 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2833 ret = SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
2834 expect(0, ret);
2835 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
2836 "WM_SETREDRAW: not forwarded to header", FALSE);
2838 DestroyWindow(hwnd);
2841 static void test_hittest(void)
2843 HWND hwnd;
2844 DWORD r;
2845 RECT bounds;
2846 LVITEMA item;
2847 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
2848 POINT pos;
2849 INT x, y;
2850 HIMAGELIST himl, himl2;
2851 HBITMAP hbmp;
2853 hwnd = create_listview_control(LVS_REPORT);
2854 ok(hwnd != NULL, "failed to create a listview window\n");
2856 /* LVS_REPORT with a single subitem (2 columns) */
2857 insert_column(hwnd, 0);
2858 insert_column(hwnd, 1);
2859 insert_item(hwnd, 0);
2861 item.iSubItem = 0;
2862 /* the only purpose of that line is to be as long as a half item rect */
2863 item.pszText = text;
2864 r = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&item);
2865 expect(TRUE, r);
2867 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
2868 expect(TRUE, r);
2869 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
2870 expect(TRUE, r);
2872 memset(&bounds, 0, sizeof(bounds));
2873 bounds.left = LVIR_BOUNDS;
2874 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
2875 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
2876 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
2877 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
2878 expect(TRUE, r);
2880 /* LVS_EX_FULLROWSELECT not set, no icons attached */
2881 x = pos.x + 50; /* column half width */
2882 y = pos.y + (bounds.bottom - bounds.top) / 2;
2883 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE, __LINE__);
2884 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2885 x = pos.x + 150; /* outside column */
2886 y = pos.y + (bounds.bottom - bounds.top) / 2;
2887 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2888 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2889 y = (bounds.bottom - bounds.top) / 2;
2890 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2891 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2892 /* outside possible client rectangle (to right) */
2893 x = pos.x + 500;
2894 y = pos.y + (bounds.bottom - bounds.top) / 2;
2895 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2896 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2897 y = (bounds.bottom - bounds.top) / 2;
2898 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2899 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2900 /* subitem returned with -1 item too */
2901 x = pos.x + 150;
2902 y = -10;
2903 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2904 /* parent client area is 100x100 by default */
2905 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
2906 x = pos.x + 150; /* outside column */
2907 y = pos.y + (bounds.bottom - bounds.top) / 2;
2908 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE, __LINE__);
2909 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2910 y = (bounds.bottom - bounds.top) / 2;
2911 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE, __LINE__);
2912 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2913 /* the same with LVS_EX_FULLROWSELECT */
2914 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
2915 x = pos.x + 150; /* outside column */
2916 y = pos.y + (bounds.bottom - bounds.top) / 2;
2917 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE, __LINE__);
2918 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2919 y = (bounds.bottom - bounds.top) / 2;
2920 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2921 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
2922 x = pos.x + 150; /* outside column */
2923 y = pos.y + (bounds.bottom - bounds.top) / 2;
2924 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2925 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2926 y = (bounds.bottom - bounds.top) / 2;
2927 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2928 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
2929 /* outside possible client rectangle (to right) */
2930 x = pos.x + 500;
2931 y = pos.y + (bounds.bottom - bounds.top) / 2;
2932 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE, __LINE__);
2933 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2934 y = (bounds.bottom - bounds.top) / 2;
2935 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE, __LINE__);
2936 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
2937 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
2938 himl = ImageList_Create(16, 16, 0, 4, 4);
2939 ok(himl != NULL, "failed to create imagelist\n");
2940 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
2941 ok(hbmp != NULL, "failed to create bitmap\n");
2942 r = ImageList_Add(himl, hbmp, 0);
2943 ok(r == 0, "should be zero\n");
2944 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
2945 ok(hbmp != NULL, "failed to create bitmap\n");
2946 r = ImageList_Add(himl, hbmp, 0);
2947 ok(r == 1, "should be one\n");
2949 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
2950 ok(r == 0, "should return zero\n");
2952 item.mask = LVIF_IMAGE;
2953 item.iImage = 0;
2954 item.iItem = 0;
2955 item.iSubItem = 0;
2956 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2957 expect(TRUE, r);
2958 /* on state icon */
2959 x = pos.x + 8;
2960 y = pos.y + (bounds.bottom - bounds.top) / 2;
2961 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE, __LINE__);
2962 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2963 y = (bounds.bottom - bounds.top) / 2;
2964 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2966 /* state icons indices are 1 based, check with valid index */
2967 item.mask = LVIF_STATE;
2968 item.state = INDEXTOSTATEIMAGEMASK(1);
2969 item.stateMask = LVIS_STATEIMAGEMASK;
2970 item.iItem = 0;
2971 item.iSubItem = 0;
2972 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
2973 expect(TRUE, r);
2974 /* on state icon */
2975 x = pos.x + 8;
2976 y = pos.y + (bounds.bottom - bounds.top) / 2;
2977 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE, __LINE__);
2978 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2979 y = (bounds.bottom - bounds.top) / 2;
2980 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE, __LINE__);
2982 himl2 = (HIMAGELIST)SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)NULL);
2983 ok(himl2 == himl, "should return handle\n");
2985 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
2986 ok(r == 0, "should return zero\n");
2987 /* on item icon */
2988 x = pos.x + 8;
2989 y = pos.y + (bounds.bottom - bounds.top) / 2;
2990 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE, __LINE__);
2991 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE, __LINE__);
2992 y = (bounds.bottom - bounds.top) / 2;
2993 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE, __LINE__);
2995 DestroyWindow(hwnd);
2998 static void test_getviewrect(void)
3000 HWND hwnd;
3001 DWORD r;
3002 RECT rect;
3003 LVITEMA item;
3005 hwnd = create_listview_control(LVS_REPORT);
3006 ok(hwnd != NULL, "failed to create a listview window\n");
3008 /* empty */
3009 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3010 expect(TRUE, r);
3012 insert_column(hwnd, 0);
3013 insert_column(hwnd, 1);
3015 memset(&item, 0, sizeof(item));
3016 item.iItem = 0;
3017 item.iSubItem = 0;
3018 SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3020 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3021 expect(TRUE, r);
3022 r = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
3023 expect(TRUE, r);
3025 rect.left = rect.right = rect.top = rect.bottom = -1;
3026 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3027 expect(TRUE, r);
3028 /* left is set to (2e31-1) - XP SP2 */
3029 expect(0, rect.right);
3030 expect(0, rect.top);
3031 expect(0, rect.bottom);
3033 /* switch to LVS_ICON */
3034 SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~LVS_REPORT);
3036 rect.left = rect.right = rect.top = rect.bottom = -1;
3037 r = SendMessage(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
3038 expect(TRUE, r);
3039 expect(0, rect.left);
3040 expect(0, rect.top);
3041 /* precise value differs for 2k, XP and Vista */
3042 ok(rect.bottom > 0, "Expected positive bottom value, got %d\n", rect.bottom);
3043 ok(rect.right > 0, "Expected positive right value, got %d\n", rect.right);
3045 DestroyWindow(hwnd);
3048 static void test_getitemposition(void)
3050 HWND hwnd, header;
3051 DWORD r;
3052 POINT pt;
3053 RECT rect;
3055 hwnd = create_listview_control(LVS_REPORT);
3056 ok(hwnd != NULL, "failed to create a listview window\n");
3057 header = subclass_header(hwnd);
3059 /* LVS_REPORT, single item, no columns added */
3060 insert_item(hwnd, 0);
3062 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3064 pt.x = pt.y = -1;
3065 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3066 expect(TRUE, r);
3067 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
3069 /* LVS_REPORT, single item, single column */
3070 insert_column(hwnd, 0);
3072 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3074 pt.x = pt.y = -1;
3075 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3076 expect(TRUE, r);
3077 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
3079 memset(&rect, 0, sizeof(rect));
3080 SendMessage(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
3081 /* some padding? */
3082 expect(2, pt.x);
3083 /* offset by header height */
3084 expect(rect.bottom - rect.top, pt.y);
3086 DestroyWindow(hwnd);
3089 static void test_columnscreation(void)
3091 HWND hwnd, header;
3092 DWORD r;
3094 hwnd = create_listview_control(LVS_REPORT);
3095 ok(hwnd != NULL, "failed to create a listview window\n");
3097 insert_item(hwnd, 0);
3099 /* headers columns aren't created automatically */
3100 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3101 ok(IsWindow(header), "Expected header handle\n");
3102 r = SendMessage(header, HDM_GETITEMCOUNT, 0, 0);
3103 expect(0, r);
3105 DestroyWindow(hwnd);
3108 static void test_getitemrect(void)
3110 HWND hwnd;
3111 HIMAGELIST himl;
3112 HBITMAP hbm;
3113 RECT rect;
3114 DWORD r;
3115 LVITEMA item;
3116 LVCOLUMNA col;
3117 INT order[2];
3118 POINT pt;
3120 /* rectangle isn't empty for empty text items */
3121 hwnd = create_listview_control(LVS_LIST);
3122 memset(&item, 0, sizeof(item));
3123 item.mask = 0;
3124 item.iItem = 0;
3125 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3126 expect(0, r);
3127 rect.left = LVIR_LABEL;
3128 SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3129 expect(0, rect.left);
3130 expect(0, rect.top);
3131 todo_wine expect(96, rect.right);
3132 DestroyWindow(hwnd);
3134 hwnd = create_listview_control(LVS_REPORT);
3135 ok(hwnd != NULL, "failed to create a listview window\n");
3137 /* empty item */
3138 memset(&item, 0, sizeof(item));
3139 item.iItem = 0;
3140 item.iSubItem = 0;
3141 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3142 expect(0, r);
3144 rect.left = LVIR_BOUNDS;
3145 rect.right = rect.top = rect.bottom = -1;
3146 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3147 expect(TRUE, r);
3149 /* zero width rectangle with no padding */
3150 expect(0, rect.left);
3151 expect(0, rect.right);
3153 insert_column(hwnd, 0);
3154 insert_column(hwnd, 1);
3156 col.mask = LVCF_WIDTH;
3157 col.cx = 50;
3158 r = SendMessage(hwnd, LVM_SETCOLUMN, 0, (LPARAM)&col);
3159 expect(TRUE, r);
3161 col.mask = LVCF_WIDTH;
3162 col.cx = 100;
3163 r = SendMessage(hwnd, LVM_SETCOLUMN, 1, (LPARAM)&col);
3164 expect(TRUE, r);
3166 rect.left = LVIR_BOUNDS;
3167 rect.right = rect.top = rect.bottom = -1;
3168 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3169 expect(TRUE, r);
3171 /* still no left padding */
3172 expect(0, rect.left);
3173 expect(150, rect.right);
3175 rect.left = LVIR_SELECTBOUNDS;
3176 rect.right = rect.top = rect.bottom = -1;
3177 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3178 expect(TRUE, r);
3179 /* padding */
3180 expect(2, rect.left);
3182 rect.left = LVIR_LABEL;
3183 rect.right = rect.top = rect.bottom = -1;
3184 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3185 expect(TRUE, r);
3186 /* padding, column width */
3187 expect(2, rect.left);
3188 expect(50, rect.right);
3190 /* no icons attached */
3191 rect.left = LVIR_ICON;
3192 rect.right = rect.top = rect.bottom = -1;
3193 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3194 expect(TRUE, r);
3195 /* padding */
3196 expect(2, rect.left);
3197 expect(2, rect.right);
3199 /* change order */
3200 order[0] = 1; order[1] = 0;
3201 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3202 expect(TRUE, r);
3203 pt.x = -1;
3204 r = SendMessage(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
3205 expect(TRUE, r);
3206 /* 1 indexed column width + padding */
3207 expect(102, pt.x);
3208 /* rect is at zero too */
3209 rect.left = LVIR_BOUNDS;
3210 rect.right = rect.top = rect.bottom = -1;
3211 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3212 expect(TRUE, r);
3213 expect(0, rect.left);
3214 /* just width sum */
3215 expect(150, rect.right);
3217 rect.left = LVIR_SELECTBOUNDS;
3218 rect.right = rect.top = rect.bottom = -1;
3219 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3220 expect(TRUE, r);
3221 /* column width + padding */
3222 expect(102, rect.left);
3224 /* back to initial order */
3225 order[0] = 0; order[1] = 1;
3226 r = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
3227 expect(TRUE, r);
3229 /* state icons */
3230 himl = ImageList_Create(16, 16, 0, 2, 2);
3231 ok(himl != NULL, "failed to create imagelist\n");
3232 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3233 ok(hbm != NULL, "failed to create bitmap\n");
3234 r = ImageList_Add(himl, hbm, 0);
3235 ok(r == 0, "should be zero\n");
3236 hbm = CreateBitmap(16, 16, 1, 1, NULL);
3237 ok(hbm != NULL, "failed to create bitmap\n");
3238 r = ImageList_Add(himl, hbm, 0);
3239 ok(r == 1, "should be one\n");
3241 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
3242 ok(r == 0, "should return zero\n");
3244 item.mask = LVIF_STATE;
3245 item.state = INDEXTOSTATEIMAGEMASK(1);
3246 item.stateMask = LVIS_STATEIMAGEMASK;
3247 item.iItem = 0;
3248 item.iSubItem = 0;
3249 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3250 expect(TRUE, r);
3252 /* icon bounds */
3253 rect.left = LVIR_ICON;
3254 rect.right = rect.top = rect.bottom = -1;
3255 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3256 expect(TRUE, r);
3257 /* padding + stateicon width */
3258 expect(18, rect.left);
3259 expect(18, rect.right);
3260 /* label bounds */
3261 rect.left = LVIR_LABEL;
3262 rect.right = rect.top = rect.bottom = -1;
3263 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3264 expect(TRUE, r);
3265 /* padding + stateicon width -> column width */
3266 expect(18, rect.left);
3267 expect(50, rect.right);
3269 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)NULL);
3270 ok(r != 0, "should return current list handle\n");
3272 r = SendMessage(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
3273 ok(r == 0, "should return zero\n");
3275 item.mask = LVIF_STATE | LVIF_IMAGE;
3276 item.iImage = 1;
3277 item.state = 0;
3278 item.stateMask = ~0;
3279 item.iItem = 0;
3280 item.iSubItem = 0;
3281 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3282 expect(TRUE, r);
3284 /* icon bounds */
3285 rect.left = LVIR_ICON;
3286 rect.right = rect.top = rect.bottom = -1;
3287 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3288 expect(TRUE, r);
3289 /* padding, icon width */
3290 expect(2, rect.left);
3291 expect(18, rect.right);
3292 /* label bounds */
3293 rect.left = LVIR_LABEL;
3294 rect.right = rect.top = rect.bottom = -1;
3295 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3296 expect(TRUE, r);
3297 /* padding + icon width -> column width */
3298 expect(18, rect.left);
3299 expect(50, rect.right);
3301 /* select bounds */
3302 rect.left = LVIR_SELECTBOUNDS;
3303 rect.right = rect.top = rect.bottom = -1;
3304 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3305 expect(TRUE, r);
3306 /* padding, column width */
3307 expect(2, rect.left);
3308 expect(50, rect.right);
3310 /* try with indentation */
3311 item.mask = LVIF_INDENT;
3312 item.iIndent = 1;
3313 item.iItem = 0;
3314 item.iSubItem = 0;
3315 r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM)&item);
3316 expect(TRUE, r);
3318 /* bounds */
3319 rect.left = LVIR_BOUNDS;
3320 rect.right = rect.top = rect.bottom = -1;
3321 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3322 expect(TRUE, r);
3323 /* padding + 1 icon width, column width */
3324 expect(0, rect.left);
3325 expect(150, rect.right);
3327 /* select bounds */
3328 rect.left = LVIR_SELECTBOUNDS;
3329 rect.right = rect.top = rect.bottom = -1;
3330 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3331 expect(TRUE, r);
3332 /* padding + 1 icon width, column width */
3333 expect(2 + 16, rect.left);
3334 expect(50, rect.right);
3336 /* label bounds */
3337 rect.left = LVIR_LABEL;
3338 rect.right = rect.top = rect.bottom = -1;
3339 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3340 expect(TRUE, r);
3341 /* padding + 2 icon widths, column width */
3342 expect(2 + 16*2, rect.left);
3343 expect(50, rect.right);
3345 /* icon bounds */
3346 rect.left = LVIR_ICON;
3347 rect.right = rect.top = rect.bottom = -1;
3348 r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
3349 expect(TRUE, r);
3350 /* padding + 1 icon width indentation, icon width */
3351 expect(2 + 16, rect.left);
3352 expect(34, rect.right);
3355 DestroyWindow(hwnd);
3358 static void test_editbox(void)
3360 HWND hwnd, hwndedit, hwndedit2;
3361 LVITEMA item;
3362 DWORD r;
3363 static CHAR testitemA[] = "testitem";
3364 static CHAR testitem1A[] = "testitem1";
3365 static CHAR buffer[10];
3367 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
3368 ok(hwnd != NULL, "failed to create a listview window\n");
3370 insert_column(hwnd, 0);
3372 memset(&item, 0, sizeof(item));
3373 item.mask = LVIF_TEXT;
3374 item.pszText = testitemA;
3375 item.iItem = 0;
3376 item.iSubItem = 0;
3377 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3378 expect(0, r);
3380 /* setting focus is necessary */
3381 SetFocus(hwnd);
3382 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3383 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3385 /* modify initial string */
3386 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
3387 expect(TRUE, r);
3388 /* return focus to listview */
3389 SetFocus(hwnd);
3391 memset(&item, 0, sizeof(item));
3392 item.mask = LVIF_TEXT;
3393 item.pszText = buffer;
3394 item.cchTextMax = 10;
3395 item.iItem = 0;
3396 item.iSubItem = 0;
3397 r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3398 expect(TRUE, r);
3400 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3402 /* send LVM_EDITLABEL on already created edit */
3403 SetFocus(hwnd);
3404 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3405 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3406 /* focus will be set to edit */
3407 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
3408 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3409 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
3411 /* creating label disabled when control isn't focused */
3412 SetFocus(0);
3413 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3414 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3416 /* check EN_KILLFOCUS handling */
3417 memset(&item, 0, sizeof(item));
3418 item.pszText = testitemA;
3419 item.iItem = 0;
3420 item.iSubItem = 0;
3421 r = SendMessage(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3422 expect(TRUE, r);
3424 SetFocus(hwnd);
3425 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3426 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3427 /* modify edit and notify control that it lost focus */
3428 r = SendMessage(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
3429 expect(TRUE, r);
3430 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
3431 expect(0, r);
3432 memset(&item, 0, sizeof(item));
3433 item.pszText = buffer;
3434 item.cchTextMax = 10;
3435 item.iItem = 0;
3436 item.iSubItem = 0;
3437 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3438 expect(lstrlen(item.pszText), r);
3439 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3440 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
3441 /* end edit without saving */
3442 SetFocus(hwnd);
3443 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3444 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3445 r = SendMessage(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
3446 expect(0, r);
3447 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
3448 "edit box - end edit, no change, escape", TRUE);
3449 /* end edit with saving */
3450 SetFocus(hwnd);
3451 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3452 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3453 r = SendMessage(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
3454 expect(0, r);
3455 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
3456 "edit box - end edit, no change, return", TRUE);
3458 memset(&item, 0, sizeof(item));
3459 item.pszText = buffer;
3460 item.cchTextMax = 10;
3461 item.iItem = 0;
3462 item.iSubItem = 0;
3463 r = SendMessage(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
3464 expect(lstrlen(item.pszText), r);
3465 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
3467 /* LVM_EDITLABEL with -1 destroys current edit */
3468 hwndedit = (HWND)SendMessage(hwnd, LVM_GETEDITCONTROL, 0, 0);
3469 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3470 /* no edit present */
3471 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
3472 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
3473 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3474 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3475 /* edit present */
3476 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3477 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -1, 0);
3478 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3479 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3480 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3481 /* check another negative value */
3482 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3483 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3484 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3485 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, -2, 0);
3486 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3487 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3488 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3489 /* and value greater than max item index */
3490 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3491 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3492 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
3493 r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
3494 hwndedit2 = (HWND)SendMessage(hwnd, LVM_EDITLABEL, r, 0);
3495 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
3496 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
3497 ok(GetFocus() == hwnd, "Expected List to be focused\n");
3499 /* messaging tests */
3500 SetFocus(hwnd);
3501 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3502 blockEdit = FALSE;
3503 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3504 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3505 /* testing only sizing messages */
3506 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
3507 "edit box create - sizing", FALSE);
3509 /* WM_COMMAND with EN_KILLFOCUS isn't forwared to parent */
3510 SetFocus(hwnd);
3511 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3512 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
3513 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3514 r = SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
3515 expect(0, r);
3516 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
3517 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
3519 DestroyWindow(hwnd);
3522 static void test_notifyformat(void)
3524 HWND hwnd, header;
3525 DWORD r;
3527 hwnd = create_listview_control(LVS_REPORT);
3528 ok(hwnd != NULL, "failed to create a listview window\n");
3530 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
3531 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
3532 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3533 expect(0, r);
3534 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
3535 /* set */
3536 r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
3537 expect(0, r);
3538 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3539 if (r == 1)
3541 r = SendMessage(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
3542 expect(1, r);
3543 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3544 expect(0, r);
3546 else
3548 win_skip("LVM_GETUNICODEFORMAT is unsupported\n");
3549 DestroyWindow(hwnd);
3550 return;
3553 DestroyWindow(hwnd);
3555 /* test failure in parent WM_NOTIFYFORMAT */
3556 notifyFormat = 0;
3557 hwnd = create_listview_control(LVS_REPORT);
3558 ok(hwnd != NULL, "failed to create a listview window\n");
3559 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3560 ok(IsWindow(header), "expected header to be created\n");
3561 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3562 expect(0, r);
3563 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3564 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3565 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
3566 ok(r != 0, "Expected valid format\n");
3568 notifyFormat = NFR_UNICODE;
3569 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
3570 expect(NFR_UNICODE, r);
3571 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3572 expect(1, r);
3573 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3574 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3576 notifyFormat = NFR_ANSI;
3577 r = SendMessage(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
3578 expect(NFR_ANSI, r);
3579 r = SendMessage(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3580 expect(0, r);
3581 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3582 ok( r == 1 || broken(r == 0), /* win9x */ "Expected 1, got %d\n", r );
3584 DestroyWindow(hwnd);
3586 /* try different unicode window combination and defaults */
3587 if (!GetModuleHandleW(NULL))
3589 win_skip("Additional notify format tests are incompatible with Win9x\n");
3590 return;
3593 hwndparentW = create_parent_window(TRUE);
3594 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
3595 if (!IsWindow(hwndparentW)) return;
3597 notifyFormat = -1;
3598 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
3599 ok(hwnd != NULL, "failed to create a listview window\n");
3600 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3601 ok(IsWindow(header), "expected header to be created\n");
3602 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3603 expect(1, r);
3604 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3605 expect(1, r);
3606 DestroyWindow(hwnd);
3607 /* receiving error code defaulting to ansi */
3608 notifyFormat = 0;
3609 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
3610 ok(hwnd != NULL, "failed to create a listview window\n");
3611 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3612 ok(IsWindow(header), "expected header to be created\n");
3613 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3614 expect(0, r);
3615 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3616 expect(1, r);
3617 DestroyWindow(hwnd);
3618 /* receiving ansi code from unicode window, use it */
3619 notifyFormat = NFR_ANSI;
3620 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
3621 ok(hwnd != NULL, "failed to create a listview window\n");
3622 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3623 ok(IsWindow(header), "expected header to be created\n");
3624 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3625 expect(0, r);
3626 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3627 expect(1, r);
3628 DestroyWindow(hwnd);
3629 /* unicode listview with ansi parent window */
3630 notifyFormat = -1;
3631 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
3632 ok(hwnd != NULL, "failed to create a listview window\n");
3633 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3634 ok(IsWindow(header), "expected header to be created\n");
3635 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3636 expect(0, r);
3637 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3638 expect(1, r);
3639 DestroyWindow(hwnd);
3640 /* unicode listview with ansi parent window, return error code */
3641 notifyFormat = 0;
3642 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
3643 ok(hwnd != NULL, "failed to create a listview window\n");
3644 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
3645 ok(IsWindow(header), "expected header to be created\n");
3646 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
3647 expect(0, r);
3648 r = SendMessage(header, HDM_GETUNICODEFORMAT, 0, 0);
3649 expect(1, r);
3650 DestroyWindow(hwnd);
3652 DestroyWindow(hwndparentW);
3655 static void test_indentation(void)
3657 HWND hwnd;
3658 LVITEMA item;
3659 DWORD r;
3661 hwnd = create_listview_control(LVS_REPORT);
3662 ok(hwnd != NULL, "failed to create a listview window\n");
3664 memset(&item, 0, sizeof(item));
3665 item.mask = LVIF_INDENT;
3666 item.iItem = 0;
3667 item.iIndent = I_INDENTCALLBACK;
3668 r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3669 expect(0, r);
3671 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3673 item.iItem = 0;
3674 item.mask = LVIF_INDENT;
3675 r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
3676 expect(TRUE, r);
3678 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3679 "get indent dispinfo", FALSE);
3681 DestroyWindow(hwnd);
3684 static INT CALLBACK DummyCompareEx(LPARAM first, LPARAM second, LPARAM param)
3686 return 0;
3689 static BOOL is_below_comctl_5(void)
3691 HWND hwnd;
3692 BOOL ret;
3694 hwnd = create_listview_control(LVS_REPORT);
3695 ok(hwnd != NULL, "failed to create a listview window\n");
3696 insert_item(hwnd, 0);
3698 ret = SendMessage(hwnd, LVM_SORTITEMSEX, 0, (LPARAM)&DummyCompareEx);
3700 DestroyWindow(hwnd);
3702 return !ret;
3705 static void test_get_set_view(void)
3707 HWND hwnd;
3708 DWORD ret;
3709 DWORD_PTR style;
3711 /* test style->view mapping */
3712 hwnd = create_listview_control(LVS_REPORT);
3713 ok(hwnd != NULL, "failed to create a listview window\n");
3715 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3716 expect(LV_VIEW_DETAILS, ret);
3718 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3719 /* LVS_ICON == 0 */
3720 SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_REPORT);
3721 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3722 expect(LV_VIEW_ICON, ret);
3724 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3725 SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_SMALLICON);
3726 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3727 expect(LV_VIEW_SMALLICON, ret);
3729 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3730 SetWindowLongPtr(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
3731 ret = SendMessage(hwnd, LVM_GETVIEW, 0, 0);
3732 expect(LV_VIEW_LIST, ret);
3734 /* switching view doesn't touch window style */
3735 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
3736 expect(1, ret);
3737 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3738 ok(style & LVS_LIST, "Expected style to be preserved\n");
3739 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
3740 expect(1, ret);
3741 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3742 ok(style & LVS_LIST, "Expected style to be preserved\n");
3743 ret = SendMessage(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
3744 expect(1, ret);
3745 style = GetWindowLongPtr(hwnd, GWL_STYLE);
3746 ok(style & LVS_LIST, "Expected style to be preserved\n");
3748 DestroyWindow(hwnd);
3751 static void test_canceleditlabel(void)
3753 HWND hwnd, hwndedit;
3754 DWORD ret;
3755 CHAR buff[10];
3756 LVITEMA itema;
3757 static CHAR test[] = "test";
3758 static const CHAR test1[] = "test1";
3760 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
3761 ok(hwnd != NULL, "failed to create a listview window\n");
3763 insert_item(hwnd, 0);
3765 /* try without edit created */
3766 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3767 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
3768 expect(TRUE, ret);
3769 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3770 "cancel edit label without edit", FALSE);
3772 /* cancel without data change */
3773 SetFocus(hwnd);
3774 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3775 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
3776 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
3777 expect(TRUE, ret);
3778 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
3780 /* cancel after data change */
3781 memset(&itema, 0, sizeof(itema));
3782 itema.pszText = test;
3783 ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
3784 expect(TRUE, ret);
3785 SetFocus(hwnd);
3786 hwndedit = (HWND)SendMessage(hwnd, LVM_EDITLABEL, 0, 0);
3787 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
3788 ret = SetWindowText(hwndedit, test1);
3789 ok(ret != 0, "Expected edit text to change\n");
3790 ret = SendMessage(hwnd, LVM_CANCELEDITLABEL, 0, 0);
3791 expect(TRUE, ret);
3792 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
3793 memset(&itema, 0, sizeof(itema));
3794 itema.pszText = buff;
3795 itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
3796 ret = SendMessage(hwnd, LVM_GETITEMTEXT, 0, (LPARAM)&itema);
3797 expect(5, ret);
3798 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
3800 DestroyWindow(hwnd);
3803 static void test_mapidindex(void)
3805 HWND hwnd;
3806 DWORD ret;
3808 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
3809 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3810 ok(hwnd != NULL, "failed to create a listview window\n");
3811 insert_item(hwnd, 0);
3812 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3813 expect(-1, ret);
3814 DestroyWindow(hwnd);
3816 hwnd = create_listview_control(LVS_REPORT);
3817 ok(hwnd != NULL, "failed to create a listview window\n");
3819 /* LVM_MAPINDEXTOID with invalid index */
3820 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3821 expect(-1, ret);
3823 insert_item(hwnd, 0);
3824 insert_item(hwnd, 1);
3826 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0);
3827 expect(-1, ret);
3828 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0);
3829 expect(-1, ret);
3831 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3832 expect(0, ret);
3833 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
3834 expect(1, ret);
3835 /* remove 0 indexed item, id retained */
3836 SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
3837 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
3838 expect(1, ret);
3839 /* new id starts from previous value */
3840 insert_item(hwnd, 1);
3841 ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
3842 expect(2, ret);
3844 /* get index by id */
3845 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0);
3846 expect(-1, ret);
3847 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0);
3848 expect(-1, ret);
3849 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0);
3850 expect(0, ret);
3851 ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0);
3852 expect(1, ret);
3854 DestroyWindow(hwnd);
3857 static void test_getitemspacing(void)
3859 HWND hwnd;
3860 DWORD ret;
3861 INT cx, cy;
3862 HIMAGELIST himl;
3863 HBITMAP hbmp;
3864 LVITEMA itema;
3866 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
3867 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
3869 /* LVS_ICON */
3870 hwnd = create_listview_control(LVS_ICON);
3871 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3872 todo_wine {
3873 expect(cx, LOWORD(ret));
3874 expect(cy, HIWORD(ret));
3876 /* now try with icons */
3877 himl = ImageList_Create(40, 40, 0, 4, 4);
3878 ok(himl != NULL, "failed to create imagelist\n");
3879 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
3880 ok(hbmp != NULL, "failed to create bitmap\n");
3881 ret = ImageList_Add(himl, hbmp, 0);
3882 expect(0, ret);
3883 ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
3884 expect(0, ret);
3886 itema.mask = LVIF_IMAGE;
3887 itema.iImage = 0;
3888 itema.iItem = 0;
3889 itema.iSubItem = 0;
3890 ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
3891 expect(0, ret);
3892 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3893 todo_wine {
3894 /* spacing + icon size returned */
3895 expect(cx + 40, LOWORD(ret));
3896 expect(cy + 40, HIWORD(ret));
3898 DestroyWindow(hwnd);
3899 /* LVS_SMALLICON */
3900 hwnd = create_listview_control(LVS_SMALLICON);
3901 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3902 todo_wine {
3903 expect(cx, LOWORD(ret));
3904 expect(cy, HIWORD(ret));
3906 DestroyWindow(hwnd);
3907 /* LVS_REPORT */
3908 hwnd = create_listview_control(LVS_REPORT);
3909 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3910 todo_wine {
3911 expect(cx, LOWORD(ret));
3912 expect(cy, HIWORD(ret));
3914 DestroyWindow(hwnd);
3915 /* LVS_LIST */
3916 hwnd = create_listview_control(LVS_LIST);
3917 ret = SendMessage(hwnd, LVM_GETITEMSPACING, FALSE, 0);
3918 todo_wine {
3919 expect(cx, LOWORD(ret));
3920 expect(cy, HIWORD(ret));
3922 DestroyWindow(hwnd);
3925 static void test_getcolumnwidth(void)
3927 HWND hwnd;
3928 DWORD ret;
3929 DWORD_PTR style;
3930 LVCOLUMNA col;
3931 LVITEMA itema;
3933 /* default column width */
3934 hwnd = create_listview_control(LVS_ICON);
3935 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3936 expect(0, ret);
3937 style = GetWindowLong(hwnd, GWL_STYLE);
3938 SetWindowLong(hwnd, GWL_STYLE, style | LVS_LIST);
3939 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3940 todo_wine expect(8, ret);
3941 style = GetWindowLong(hwnd, GWL_STYLE) & ~LVS_LIST;
3942 SetWindowLong(hwnd, GWL_STYLE, style | LVS_REPORT);
3943 col.mask = 0;
3944 ret = SendMessage(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
3945 expect(0, ret);
3946 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3947 expect(10, ret);
3948 DestroyWindow(hwnd);
3950 /* default column width with item added */
3951 hwnd = create_listview_control(LVS_LIST);
3952 memset(&itema, 0, sizeof(itema));
3953 SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
3954 ret = SendMessage(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
3955 expect(96, ret);
3956 DestroyWindow(hwnd);
3959 static void test_scrollnotify(void)
3961 HWND hwnd;
3962 DWORD ret;
3964 hwnd = create_listview_control(LVS_REPORT);
3966 insert_column(hwnd, 0);
3967 insert_column(hwnd, 1);
3968 insert_item(hwnd, 0);
3970 /* make it scrollable - resize */
3971 ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3972 expect(TRUE, ret);
3973 ret = SendMessage(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3974 expect(TRUE, ret);
3976 /* try with dummy call */
3977 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3978 ret = SendMessage(hwnd, LVM_SCROLL, 0, 0);
3979 expect(TRUE, ret);
3980 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
3981 "scroll notify 1", TRUE);
3983 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3984 ret = SendMessage(hwnd, LVM_SCROLL, 1, 0);
3985 expect(TRUE, ret);
3986 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
3987 "scroll notify 2", TRUE);
3989 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3990 ret = SendMessage(hwnd, LVM_SCROLL, 1, 1);
3991 expect(TRUE, ret);
3992 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
3993 "scroll notify 3", TRUE);
3995 DestroyWindow(hwnd);
3998 static void test_LVS_EX_TRANSPARENTBKGND(void)
4000 HWND hwnd;
4001 DWORD ret;
4002 HDC hdc;
4004 hwnd = create_listview_control(LVS_REPORT);
4006 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4007 expect(TRUE, ret);
4009 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4010 LVS_EX_TRANSPARENTBKGND);
4012 ret = SendMessage(hwnd, LVM_GETBKCOLOR, 0, 0);
4013 if (ret != CLR_NONE)
4015 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
4016 DestroyWindow(hwnd);
4017 return;
4020 /* try to set some back color and check this style bit */
4021 ret = SendMessage(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
4022 expect(TRUE, ret);
4023 ret = SendMessage(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
4024 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
4026 /* now test what this style actually does */
4027 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
4028 LVS_EX_TRANSPARENTBKGND);
4030 hdc = GetWindowDC(hwndparent);
4032 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4033 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
4034 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
4035 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
4037 ReleaseDC(hwndparent, hdc);
4039 DestroyWindow(hwnd);
4042 static void test_approximate_viewrect(void)
4044 HWND hwnd;
4045 DWORD ret;
4046 INT cx, cy;
4047 HIMAGELIST himl;
4048 HBITMAP hbmp;
4049 LVITEMA itema;
4050 static CHAR test[] = "abracadabra, a very long item label";
4052 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4053 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4055 hwnd = create_listview_control(LVS_ICON);
4056 himl = ImageList_Create(40, 40, 0, 4, 4);
4057 ok(himl != NULL, "failed to create imagelist\n");
4058 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
4059 ok(hbmp != NULL, "failed to create bitmap\n");
4060 ret = ImageList_Add(himl, hbmp, 0);
4061 expect(0, ret);
4062 ret = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
4063 expect(0, ret);
4065 itema.mask = LVIF_IMAGE;
4066 itema.iImage = 0;
4067 itema.iItem = 0;
4068 itema.iSubItem = 0;
4069 ret = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM)&itema);
4070 expect(0, ret);
4072 ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
4073 if (ret == 0)
4075 /* version 4.0 */
4076 win_skip("LVM_SETICONSPACING unimplemented. Skipping.\n");
4077 return;
4080 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4081 ok(MAKELONG(77,827)==ret,"Incorrect Approximate rect\n");
4083 ret = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
4084 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
4085 ok(MAKELONG(102,302)==ret,"Incorrect Approximate rect\n");
4087 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4088 ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
4090 itema.pszText = test;
4091 ret = SendMessage(hwnd, LVM_SETITEMTEXT, 0, (LPARAM)&itema);
4092 expect(TRUE, ret);
4093 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
4094 ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
4096 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
4097 ok(MAKELONG(52,2)==ret,"Incorrect Approximate rect\n");
4098 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
4099 ok(MAKELONG(52,52)==ret,"Incorrect Approximate rect\n");
4100 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
4101 ok(MAKELONG(102,52)==ret,"Incorrect Approximate rect\n");
4102 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
4103 ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n");
4104 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
4105 ok(MAKELONG(102,102)==ret,"Incorrect Approximate rect\n");
4106 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
4107 ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n");
4108 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
4109 ok(MAKELONG(102,152)==ret,"Incorrect Approximate rect\n");
4110 ret = SendMessage(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
4111 ok(MAKELONG(152,152)==ret,"Incorrect Approximate rect\n");
4113 DestroyWindow(hwnd);
4116 static void test_finditem(void)
4118 LVFINDINFOA fi;
4119 static char f[5];
4120 HWND hwnd;
4121 DWORD r;
4123 hwnd = create_listview_control(LVS_REPORT);
4124 insert_item(hwnd, 0);
4126 memset(&fi, 0, sizeof(fi));
4128 /* full string search, inserted text was "foo" */
4129 strcpy(f, "foo");
4130 fi.flags = LVFI_STRING;
4131 fi.psz = f;
4132 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4133 expect(0, r);
4134 /* partial string search, inserted text was "foo" */
4135 strcpy(f, "fo");
4136 fi.flags = LVFI_STRING | LVFI_PARTIAL;
4137 fi.psz = f;
4138 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4139 expect(0, r);
4140 /* partial string search, part after start char */
4141 strcpy(f, "oo");
4142 fi.flags = LVFI_STRING | LVFI_PARTIAL;
4143 fi.psz = f;
4144 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4145 expect(-1, r);
4147 /* try with LVFI_SUBSTRING */
4148 strcpy(f, "fo");
4149 fi.flags = LVFI_SUBSTRING;
4150 fi.psz = f;
4151 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4152 if (r == -1)
4154 win_skip("LVFI_SUBSTRING not supported\n");
4155 DestroyWindow(hwnd);
4156 return;
4158 expect(0, r);
4159 strcpy(f, "f");
4160 fi.flags = LVFI_SUBSTRING;
4161 fi.psz = f;
4162 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4163 expect(0, r);
4164 strcpy(f, "o");
4165 fi.flags = LVFI_SUBSTRING;
4166 fi.psz = f;
4167 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4168 expect(-1, r);
4170 strcpy(f, "f");
4171 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
4172 fi.psz = f;
4173 r = SendMessage(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
4174 expect(0, r);
4176 DestroyWindow(hwnd);
4179 static void test_LVS_EX_HEADERINALLVIEWS(void)
4181 HWND hwnd, header;
4182 DWORD style;
4184 hwnd = create_listview_control(LVS_ICON);
4186 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4187 LVS_EX_HEADERINALLVIEWS);
4189 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4190 if (!IsWindow(header))
4192 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
4193 DestroyWindow(hwnd);
4194 return;
4197 /* LVS_NOCOLUMNHEADER works as before */
4198 style = GetWindowLongA(hwnd, GWL_STYLE);
4199 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
4200 style = GetWindowLongA(header, GWL_STYLE);
4201 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
4202 style = GetWindowLongA(hwnd, GWL_STYLE);
4203 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
4204 style = GetWindowLongA(header, GWL_STYLE);
4205 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
4207 /* try to remove style */
4208 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
4209 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4210 ok(IsWindow(header), "Expected header to be created\n");
4211 style = GetWindowLongA(header, GWL_STYLE);
4212 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
4214 DestroyWindow(hwnd);
4216 /* check other styles */
4217 hwnd = create_listview_control(LVS_LIST);
4218 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4219 LVS_EX_HEADERINALLVIEWS);
4220 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4221 ok(IsWindow(header), "Expected header to be created\n");
4222 DestroyWindow(hwnd);
4224 hwnd = create_listview_control(LVS_SMALLICON);
4225 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4226 LVS_EX_HEADERINALLVIEWS);
4227 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4228 ok(IsWindow(header), "Expected header to be created\n");
4229 DestroyWindow(hwnd);
4231 hwnd = create_listview_control(LVS_REPORT);
4232 SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
4233 LVS_EX_HEADERINALLVIEWS);
4234 header = (HWND)SendMessage(hwnd, LVM_GETHEADER, 0, 0);
4235 ok(IsWindow(header), "Expected header to be created\n");
4236 DestroyWindow(hwnd);
4239 static void test_hover(void)
4241 HWND hwnd;
4242 DWORD r;
4244 hwnd = create_listview_control(LVS_ICON);
4246 /* test WM_MOUSEHOVER forwarding */
4247 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4248 r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
4249 expect(0, r);
4250 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
4251 g_block_hover = TRUE;
4252 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4253 r = SendMessage(hwnd, WM_MOUSEHOVER, 0, 0);
4254 expect(0, r);
4255 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
4256 g_block_hover = FALSE;
4258 r = SendMessage(hwnd, LVM_SETHOVERTIME, 0, 500);
4259 expect(HOVER_DEFAULT, r);
4260 r = SendMessage(hwnd, LVM_GETHOVERTIME, 0, 0);
4261 expect(500, r);
4263 DestroyWindow(hwnd);
4266 START_TEST(listview)
4268 HMODULE hComctl32;
4269 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
4271 ULONG_PTR ctx_cookie;
4272 HANDLE hCtx;
4273 HWND hwnd;
4275 hComctl32 = GetModuleHandleA("comctl32.dll");
4276 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
4277 if (pInitCommonControlsEx)
4279 INITCOMMONCONTROLSEX iccex;
4280 iccex.dwSize = sizeof(iccex);
4281 iccex.dwICC = ICC_LISTVIEW_CLASSES;
4282 pInitCommonControlsEx(&iccex);
4284 else
4285 InitCommonControls();
4287 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
4289 hwndparent = create_parent_window(FALSE);
4290 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4292 g_is_below_5 = is_below_comctl_5();
4294 test_images();
4295 test_checkboxes();
4296 test_items();
4297 test_create();
4298 test_redraw();
4299 test_customdraw();
4300 test_icon_spacing();
4301 test_color();
4302 test_item_count();
4303 test_item_position();
4304 test_columns();
4305 test_getorigin();
4306 test_multiselect();
4307 test_getitemrect();
4308 test_subitem_rect();
4309 test_sorting();
4310 test_ownerdata();
4311 test_norecompute();
4312 test_nosortheader();
4313 test_setredraw();
4314 test_hittest();
4315 test_getviewrect();
4316 test_getitemposition();
4317 test_columnscreation();
4318 test_editbox();
4319 test_notifyformat();
4320 test_indentation();
4321 test_getitemspacing();
4322 test_getcolumnwidth();
4323 test_approximate_viewrect();
4324 test_finditem();
4325 test_hover();
4327 if (!load_v6_module(&ctx_cookie, &hCtx))
4329 DestroyWindow(hwndparent);
4330 return;
4333 /* this is a XP SP3 failure workaround */
4334 hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
4335 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT,
4336 0, 0, 100, 100,
4337 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
4338 if (!IsWindow(hwnd))
4340 win_skip("FIXME: failed to create ListView window.\n");
4341 unload_v6_module(ctx_cookie, hCtx);
4342 DestroyWindow(hwndparent);
4343 return;
4345 else
4346 DestroyWindow(hwnd);
4348 /* comctl32 version 6 tests start here */
4349 test_get_set_view();
4350 test_canceleditlabel();
4351 test_mapidindex();
4352 test_scrollnotify();
4353 test_LVS_EX_TRANSPARENTBKGND();
4354 test_LVS_EX_HEADERINALLVIEWS();
4356 unload_v6_module(ctx_cookie, hCtx);
4358 DestroyWindow(hwndparent);