ntdll: Use a separate memory allocation for the kernel stack.
[wine.git] / dlls / comctl32 / tests / listview.c
blobb1cb0ef16c2e2c020561cbf2e519e541444f48c2
1 /*
2 * ListView tests
4 * Copyright 2006 Mike McCormack for CodeWeavers
5 * Copyright 2007 George Gov
6 * Copyright 2009-2014 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>
26 #include <objbase.h>
28 #include "wine/test.h"
29 #include "v6util.h"
30 #include "msg.h"
32 static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
33 static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
34 static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
35 static BOOL (WINAPI *p_TrackMouseEvent)(TRACKMOUSEEVENT *);
37 enum seq_index {
38 PARENT_SEQ_INDEX,
39 PARENT_FULL_SEQ_INDEX,
40 PARENT_CD_SEQ_INDEX,
41 PARENT_ODSTATECHANGED_SEQ_INDEX,
42 LISTVIEW_SEQ_INDEX,
43 EDITBOX_SEQ_INDEX,
44 COMBINED_SEQ_INDEX,
45 NUM_MSG_SEQUENCES
48 #define LISTVIEW_ID 0
49 #define HEADER_ID 1
51 #define expect(expected,got) expect_(__LINE__, expected, got)
52 static inline void expect_(unsigned line, DWORD expected, DWORD got)
54 ok_(__FILE__, line)(expected == got, "Expected %ld, got %ld\n", expected, got);
57 #define expect2(expected1, expected2, got1, got2) expect2_(__LINE__, expected1, expected2, got1, got2)
58 static inline void expect2_(unsigned line, DWORD expected1, DWORD expected2, DWORD got1, DWORD got2)
60 ok_(__FILE__, line)(expected1 == got1 && expected2 == got2,
61 "expected (%ld,%ld), got (%ld,%ld)\n",
62 expected1, expected2, got1, got2);
65 static HWND hwndparent, hwndparentW;
66 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
67 static BOOL blockEdit;
68 /* return nonzero on NM_HOVER */
69 static BOOL g_block_hover;
70 /* notification data for LVN_ITEMCHANGED */
71 static NMLISTVIEW g_nmlistview;
72 /* notification data for LVN_ITEMCHANGING */
73 static NMLISTVIEW g_nmlistview_changing;
74 /* format reported to control:
75 -1 falls to defproc, anything else returned */
76 static INT notifyFormat;
77 /* item data passed to LVN_GETDISPINFOA */
78 static LVITEMA g_itema;
79 /* alter notification code A->W */
80 static BOOL g_disp_A_to_W;
81 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
82 static NMLVDISPINFOA g_editbox_disp_info;
83 /* when this is set focus will be tested on LVN_DELETEITEM */
84 static BOOL g_focus_test_LVN_DELETEITEM;
85 /* Whether to send WM_KILLFOCUS to the edit control during LVN_ENDLABELEDIT */
86 static BOOL g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT;
88 static HWND subclass_editbox(HWND hwndListview);
90 static void init_functions(void)
92 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
94 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
95 X(ImageList_Create);
96 X(ImageList_Destroy);
97 X(ImageList_Add);
98 X(_TrackMouseEvent);
99 #undef X
102 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
104 static const struct message create_ownerdrawfixed_parent_seq[] = {
105 { WM_NOTIFYFORMAT, sent },
106 { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
107 { WM_MEASUREITEM, sent },
108 { WM_PARENTNOTIFY, sent },
109 { 0 }
112 static const struct message redraw_listview_seq[] = {
113 { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
114 { WM_PAINT, sent|id, 0, 0, HEADER_ID },
115 { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
116 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
117 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
118 { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
119 { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
120 { 0 }
123 static const struct message listview_icon_spacing_seq[] = {
124 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
125 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
126 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
127 { 0 }
130 static const struct message listview_color_seq[] = {
131 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
132 { LVM_GETBKCOLOR, sent },
133 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
134 { LVM_GETTEXTCOLOR, sent },
135 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
136 { LVM_GETTEXTBKCOLOR, sent },
138 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
139 { LVM_GETBKCOLOR, sent },
140 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
141 { LVM_GETTEXTCOLOR, sent },
142 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
143 { LVM_GETTEXTBKCOLOR, sent },
145 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
146 { LVM_GETBKCOLOR, sent },
147 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
148 { LVM_GETTEXTCOLOR, sent },
149 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
150 { LVM_GETTEXTBKCOLOR, sent },
152 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
153 { LVM_GETBKCOLOR, sent },
154 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
155 { LVM_GETTEXTCOLOR, sent },
156 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
157 { LVM_GETTEXTBKCOLOR, sent },
158 { 0 }
161 static const struct message listview_item_count_seq[] = {
162 { LVM_GETITEMCOUNT, sent },
163 { LVM_INSERTITEMA, sent },
164 { LVM_INSERTITEMA, sent },
165 { LVM_INSERTITEMA, sent },
166 { LVM_GETITEMCOUNT, sent },
167 { LVM_DELETEITEM, sent|wparam, 2 },
168 { WM_NCPAINT, sent|optional },
169 { WM_ERASEBKGND, sent|optional },
170 { LVM_GETITEMCOUNT, sent },
171 { LVM_DELETEALLITEMS, sent },
172 { LVM_GETITEMCOUNT, sent },
173 { LVM_INSERTITEMA, sent },
174 { LVM_INSERTITEMA, sent },
175 { LVM_GETITEMCOUNT, sent },
176 { LVM_INSERTITEMA, sent },
177 { LVM_GETITEMCOUNT, sent },
178 { 0 }
181 static const struct message listview_itempos_seq[] = {
182 { LVM_INSERTITEMA, sent },
183 { LVM_INSERTITEMA, sent },
184 { LVM_INSERTITEMA, sent },
185 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
186 { WM_NCPAINT, sent|optional },
187 { WM_ERASEBKGND, sent|optional },
188 { LVM_GETITEMPOSITION, sent|wparam, 1 },
189 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
190 { LVM_GETITEMPOSITION, sent|wparam, 2 },
191 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
192 { LVM_GETITEMPOSITION, sent|wparam, 0 },
193 { 0 }
196 static const struct message listview_ownerdata_switchto_seq[] = {
197 { WM_STYLECHANGING, sent },
198 { WM_STYLECHANGED, sent },
199 { 0 }
202 static const struct message listview_getorderarray_seq[] = {
203 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
204 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
205 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
206 { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
207 { 0 }
210 static const struct message listview_setorderarray_seq[] = {
211 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
212 { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
213 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
214 { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
215 { 0 }
218 static const struct message empty_seq[] = {
219 { 0 }
222 static const struct message parent_focus_change_ownerdata_seq[] = {
223 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
224 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
225 { 0 }
228 static const struct message forward_erasebkgnd_parent_seq[] = {
229 { WM_ERASEBKGND, sent },
230 { 0 }
233 static const struct message ownerdata_select_focus_parent_seq[] = {
234 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
235 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
236 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
237 { 0 }
240 static const struct message ownerdata_setstate_all_parent_seq[] = {
241 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
242 { 0 }
245 static const struct message ownerdata_defocus_all_parent_seq[] = {
246 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
247 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
248 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
249 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
250 { 0 }
253 static const struct message ownerdata_deselect_all_parent_seq[] = {
254 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
255 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
256 { 0 }
259 static const struct message ownerdata_multiselect_select_0_to_1_odstatechanged_seq[] = {
260 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
261 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
262 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
263 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
264 { 0 }
267 static const struct message ownerdata_multiselect_select_0_odstatechanged_seq[] = {
268 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
269 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
270 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
271 { 0 }
274 static const struct message ownerdata_multiselect_select_0_modkey_odstatechanged_seq[] = {
275 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
276 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
277 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
278 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
279 { 0 }
282 static const struct message ownerdata_multiselect_move_0_to_1_odstatechanged_seq[] = {
283 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
284 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
285 { 0 }
288 static const struct message ownerdata_multiselect_select_0_to_2_odstatechanged_seq[] = {
289 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
290 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
291 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
292 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
293 { 0 }
296 static const struct message ownerdata_multiselect_select_3_odstatechanged_seq[] = {
297 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
298 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
299 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
300 { 0 }
303 static const struct message ownerdata_multiselect_select_3_modkey_odstatechanged_seq[] = {
304 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
305 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
306 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
307 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
308 { 0 }
311 static const struct message ownerdata_multiselect_select_3_to_2_odstatechanged_seq[] = {
312 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
313 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
314 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
315 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
316 { 0 }
319 static const struct message ownerdata_multiselect_move_3_to_2_odstatechanged_seq[] = {
320 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
321 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
322 { 0 }
325 static const struct message ownerdata_multiselect_select_3_to_1_odstatechanged_seq[] = {
326 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
327 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
328 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
329 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
330 { 0 }
333 static const struct message change_all_parent_seq[] = {
334 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
335 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
337 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
338 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
340 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
341 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
343 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
344 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
346 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
347 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
348 { 0 }
351 static const struct message changing_all_parent_seq[] = {
352 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
353 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
354 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
355 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
356 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
357 { 0 }
360 static const struct message textcallback_set_again_parent_seq[] = {
361 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
362 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
363 { 0 }
366 static const struct message single_getdispinfo_parent_seq[] = {
367 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
368 { 0 }
371 static const struct message getitemposition_seq1[] = {
372 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
373 { 0 }
376 static const struct message getitemposition_seq2[] = {
377 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
378 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
379 { 0 }
382 static const struct message getsubitemrect_seq[] = {
383 { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
384 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
385 { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
386 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
387 { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
388 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
389 { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
390 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
391 { 0 }
394 static const struct message editbox_create_pos[] = {
395 /* sequence sent after LVN_BEGINLABELEDIT */
396 /* next two are 4.7x specific */
397 { WM_WINDOWPOSCHANGING, sent },
398 { WM_WINDOWPOSCHANGED, sent|optional },
400 { WM_WINDOWPOSCHANGING, sent|optional },
401 { WM_NCCALCSIZE, sent },
402 { WM_WINDOWPOSCHANGED, sent },
403 { WM_MOVE, sent|defwinproc },
404 { WM_SIZE, sent|defwinproc },
405 /* the rest is todo, skipped in 4.7x */
406 { WM_WINDOWPOSCHANGING, sent|optional },
407 { WM_WINDOWPOSCHANGED, sent|optional },
408 { 0 }
411 static const struct message scroll_parent_seq[] = {
412 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
413 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
414 { 0 }
417 static const struct message setredraw_seq[] = {
418 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
419 { 0 }
422 static const struct message lvs_ex_transparentbkgnd_seq[] = {
423 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
424 { 0 }
427 static const struct message edit_end_nochange[] = {
428 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
429 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
430 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
431 { 0 }
434 static const struct message hover_parent[] = {
435 { WM_GETDLGCODE, sent }, /* todo_wine */
436 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
437 { 0 }
440 static const struct message listview_destroy[] = {
441 { 0x0090, sent|optional }, /* Vista */
442 { WM_PARENTNOTIFY, sent },
443 { WM_SHOWWINDOW, sent },
444 { WM_WINDOWPOSCHANGING, sent },
445 { WM_WINDOWPOSCHANGED, sent|optional },
446 { WM_DESTROY, sent },
447 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
448 { WM_NCDESTROY, sent },
449 { 0 }
452 static const struct message listview_ownerdata_destroy[] = {
453 { 0x0090, sent|optional }, /* Vista */
454 { WM_PARENTNOTIFY, sent },
455 { WM_SHOWWINDOW, sent },
456 { WM_WINDOWPOSCHANGING, sent },
457 { WM_WINDOWPOSCHANGED, sent|optional },
458 { WM_DESTROY, sent },
459 { WM_NCDESTROY, sent },
460 { 0 }
463 static const struct message listview_ownerdata_deleteall[] = {
464 { LVM_DELETEALLITEMS, sent },
465 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
466 { 0 }
469 static const struct message listview_header_changed_seq[] = {
470 { LVM_SETCOLUMNA, sent },
471 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
472 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
473 { 0 }
476 static const struct message parent_header_click_seq[] = {
477 { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
478 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
479 { 0 }
482 static const struct message parent_header_divider_dclick_seq[] = {
483 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
484 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
485 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
486 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
487 { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
488 { 0 }
491 static const struct message listview_set_imagelist[] = {
492 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
493 { 0 }
496 static const struct message listview_header_set_imagelist[] = {
497 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
498 { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
499 { 0 }
502 static const struct message parent_report_cd_seq[] = {
503 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
504 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
505 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
506 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
507 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
508 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
509 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
510 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
511 { 0 }
514 static const struct message parent_list_cd_seq[] = {
515 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
516 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
517 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
518 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
519 { 0 }
522 static const struct message listview_end_label_edit[] = {
523 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
524 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING},
525 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
526 { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
527 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
528 { 0 }
531 static const struct message listview_end_label_edit_kill_focus[] = {
532 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
533 { WM_COMMAND, sent|id|optional, 0, 0, EN_KILLFOCUS }, /* todo: not sent by wine yet */
534 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
535 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
536 { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
537 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
538 { 0 }
541 static void hold_key(int vk)
543 BYTE kstate[256];
544 BOOL res;
546 res = GetKeyboardState(kstate);
547 ok(res, "GetKeyboardState failed.\n");
548 kstate[vk] |= 0x80;
549 res = SetKeyboardState(kstate);
550 ok(res, "SetKeyboardState failed.\n");
553 static void release_key(int vk)
555 BYTE kstate[256];
556 BOOL res;
558 res = GetKeyboardState(kstate);
559 ok(res, "GetKeyboardState failed.\n");
560 kstate[vk] &= ~0x80;
561 res = SetKeyboardState(kstate);
562 ok(res, "SetKeyboardState failed.\n");
565 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
567 static LONG defwndproc_counter = 0;
568 LRESULT ret;
569 struct message msg;
571 msg.message = message;
572 msg.flags = sent|wparam|lparam;
573 if (defwndproc_counter) msg.flags |= defwinproc;
574 msg.wParam = wParam;
575 msg.lParam = lParam;
576 if (message == WM_NOTIFY && lParam)
578 NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
580 msg.id = nmlv->hdr.code;
581 if (msg.id == LVN_ITEMCHANGING || msg.id == LVN_ITEMCHANGED)
583 msg.wParam = nmlv->iItem;
584 msg.lParam = nmlv->uChanged;
587 if (message == WM_COMMAND) msg.id = HIWORD(wParam);
589 /* log system messages, except for painting */
590 if (message < WM_USER &&
591 message != WM_PAINT &&
592 message != WM_ERASEBKGND &&
593 message != WM_NCPAINT &&
594 message != WM_NCHITTEST &&
595 message != WM_GETTEXT &&
596 message != WM_GETICON &&
597 message != WM_DEVICECHANGE)
599 add_message(sequences, PARENT_SEQ_INDEX, &msg);
600 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
602 /* log change messages for single and multiple items changing in ownerdata listviews */
603 if (message == WM_NOTIFY && (msg.id == LVN_ITEMCHANGED || msg.id == LVN_ODSTATECHANGED))
604 add_message(sequences, PARENT_ODSTATECHANGED_SEQ_INDEX, &msg);
606 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
608 switch (message)
610 case WM_NOTIFY:
612 switch (((NMHDR*)lParam)->code)
614 case LVN_BEGINLABELEDITA:
616 HWND edit = NULL;
618 /* subclass edit box */
619 if (!blockEdit)
620 edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
622 if (edit)
624 INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
625 ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
626 "text limit %d, expected 259\n", len);
629 return blockEdit;
631 case LVN_ENDLABELEDITA:
633 HWND edit;
635 /* always accept new item text */
636 NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
637 g_editbox_disp_info = *di;
639 /* edit control still available from this notification */
640 edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
641 ok(IsWindow(edit), "expected valid edit control handle\n");
642 ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
644 if (g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT)
645 SendMessageA(edit, WM_KILLFOCUS, 0, 0);
647 return TRUE;
649 case LVN_ITEMCHANGING:
651 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
652 g_nmlistview_changing = *nmlv;
654 break;
655 case LVN_ITEMCHANGED:
657 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
658 g_nmlistview = *nmlv;
660 break;
661 case LVN_GETDISPINFOA:
663 NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
664 g_itema = dispinfo->item;
666 if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
668 dispinfo->hdr.code = LVN_GETDISPINFOW;
669 lstrcpyW((WCHAR *)dispinfo->item.pszText, L"TEST");
672 /* test control buffer size for text, 10 used to mask cases when control
673 is using caller buffer to process LVM_GETITEM for example */
674 if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
675 ok(dispinfo->item.cchTextMax == 260 ||
676 broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
677 "buffer size %d\n", dispinfo->item.cchTextMax);
679 break;
680 case LVN_DELETEITEM:
681 if (g_focus_test_LVN_DELETEITEM)
683 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
684 UINT state;
686 state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
687 ok(state == 0, "got state %x\n", state);
689 break;
690 case NM_HOVER:
691 if (g_block_hover) return 1;
692 break;
694 break;
696 case WM_NOTIFYFORMAT:
698 /* force to return format */
699 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
700 break;
704 defwndproc_counter++;
705 if (IsWindowUnicode(hwnd))
706 ret = DefWindowProcW(hwnd, message, wParam, lParam);
707 else
708 ret = DefWindowProcA(hwnd, message, wParam, lParam);
709 defwndproc_counter--;
711 return ret;
714 static BOOL register_parent_wnd_class(BOOL Unicode)
716 WNDCLASSA clsA;
717 WNDCLASSW clsW;
719 if (Unicode)
721 clsW.style = 0;
722 clsW.lpfnWndProc = parent_wnd_proc;
723 clsW.cbClsExtra = 0;
724 clsW.cbWndExtra = 0;
725 clsW.hInstance = GetModuleHandleW(NULL);
726 clsW.hIcon = 0;
727 clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
728 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
729 clsW.lpszMenuName = NULL;
730 clsW.lpszClassName = L"Listview test parentW";
732 else
734 clsA.style = 0;
735 clsA.lpfnWndProc = parent_wnd_proc;
736 clsA.cbClsExtra = 0;
737 clsA.cbWndExtra = 0;
738 clsA.hInstance = GetModuleHandleA(NULL);
739 clsA.hIcon = 0;
740 clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
741 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
742 clsA.lpszMenuName = NULL;
743 clsA.lpszClassName = "Listview test parent class";
746 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
749 static HWND create_parent_window(BOOL Unicode)
751 HWND hwnd;
753 if (!register_parent_wnd_class(Unicode))
754 return NULL;
756 blockEdit = FALSE;
757 notifyFormat = -1;
759 if (Unicode)
760 hwnd = CreateWindowExW(0, L"Listview test parentW", L"testparentnameW",
761 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
762 WS_MAXIMIZEBOX | WS_VISIBLE,
763 0, 0, 100, 100,
764 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
765 else
766 hwnd = CreateWindowExA(0, "Listview test parent class",
767 "Listview test parent window",
768 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
769 WS_MAXIMIZEBOX | WS_VISIBLE,
770 0, 0, 100, 100,
771 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
772 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
773 return hwnd;
776 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
778 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
779 static LONG defwndproc_counter = 0;
780 LRESULT ret;
781 struct message msg;
783 msg.message = message;
784 msg.flags = sent|wparam|lparam;
785 if (defwndproc_counter) msg.flags |= defwinproc;
786 msg.wParam = wParam;
787 msg.lParam = lParam;
788 msg.id = LISTVIEW_ID;
789 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
790 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
792 defwndproc_counter++;
793 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
794 defwndproc_counter--;
795 return ret;
798 static HWND create_listview_control(DWORD style)
800 WNDPROC oldproc;
801 HWND hwnd;
802 RECT rect;
804 GetClientRect(hwndparent, &rect);
805 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
806 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
807 0, 0, rect.right, rect.bottom,
808 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
809 ok(hwnd != NULL, "gle=%ld\n", GetLastError());
811 if (!hwnd) return NULL;
813 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
814 (LONG_PTR)listview_subclass_proc);
815 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
817 return hwnd;
820 /* unicode listview window with specified parent */
821 static HWND create_listview_controlW(DWORD style, HWND parent)
823 WNDPROC oldproc;
824 HWND hwnd;
825 RECT rect;
827 GetClientRect(parent, &rect);
828 hwnd = CreateWindowExW(0, WC_LISTVIEWW, L"foo",
829 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
830 0, 0, rect.right, rect.bottom,
831 parent, NULL, GetModuleHandleW(NULL), NULL);
832 ok(hwnd != NULL, "gle=%ld\n", GetLastError());
834 if (!hwnd) return NULL;
836 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
837 (LONG_PTR)listview_subclass_proc);
838 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
840 return hwnd;
844 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
846 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
847 static LONG defwndproc_counter = 0;
848 struct message msg = { 0 };
849 LRESULT ret;
851 msg.message = message;
852 msg.flags = sent|wparam|lparam;
853 if (defwndproc_counter) msg.flags |= defwinproc;
854 msg.wParam = wParam;
855 msg.lParam = lParam;
856 msg.id = HEADER_ID;
857 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
859 defwndproc_counter++;
860 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
861 defwndproc_counter--;
862 return ret;
865 static HWND subclass_header(HWND hwndListview)
867 WNDPROC oldproc;
868 HWND hwnd;
870 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
871 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
872 (LONG_PTR)header_subclass_proc);
873 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
875 return hwnd;
878 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
880 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
881 static LONG defwndproc_counter = 0;
882 struct message msg = { 0 };
883 LRESULT ret;
885 msg.message = message;
886 msg.flags = sent|wparam|lparam;
887 if (defwndproc_counter) msg.flags |= defwinproc;
888 msg.wParam = wParam;
889 msg.lParam = lParam;
891 /* all we need is sizing */
892 if (message == WM_WINDOWPOSCHANGING ||
893 message == WM_NCCALCSIZE ||
894 message == WM_WINDOWPOSCHANGED ||
895 message == WM_MOVE ||
896 message == WM_SIZE)
898 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
901 defwndproc_counter++;
902 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
903 defwndproc_counter--;
904 return ret;
907 static HWND subclass_editbox(HWND hwndListview)
909 WNDPROC oldproc;
910 HWND hwnd;
912 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
913 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
914 (LONG_PTR)editbox_subclass_proc);
915 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
917 return hwnd;
920 /* Performs a single LVM_HITTEST test */
921 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
922 BOOL todo_item, BOOL todo_flags, int line)
924 LVHITTESTINFO lpht;
925 INT ret;
927 lpht.pt.x = x;
928 lpht.pt.y = y;
929 lpht.iSubItem = 10;
931 ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
933 todo_wine_if(todo_item)
935 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
936 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
937 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
940 if (todo_flags)
942 todo_wine
943 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
945 else if (broken_flags)
946 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
947 "Expected flags %x, got %x\n", flags, lpht.flags);
948 else
949 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
952 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
954 /* Performs a single LVM_SUBITEMHITTEST test */
955 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
956 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
958 LVHITTESTINFO lpht;
959 INT ret;
961 lpht.pt.x = x;
962 lpht.pt.y = y;
964 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
966 todo_wine_if(todo_item)
968 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
969 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
972 todo_wine_if(todo_subitem)
973 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
975 todo_wine_if(todo_flags)
976 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
979 #define test_lvm_subitemhittest(a,b,c,d,e,f,g,h,i) test_lvm_subitemhittest_(a,b,c,d,e,f,g,h,i,__LINE__)
981 static void test_images(void)
983 HWND hwnd;
984 INT r;
985 LVITEMA item;
986 HIMAGELIST himl;
987 HBITMAP hbmp;
988 RECT r1, r2;
989 static CHAR hello[] = "hello";
991 himl = pImageList_Create(40, 40, 0, 4, 4);
992 ok(himl != NULL, "failed to create imagelist\n");
994 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
995 ok(hbmp != NULL, "failed to create bitmap\n");
997 r = pImageList_Add(himl, hbmp, 0);
998 ok(r == 0, "should be zero\n");
1000 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_OWNERDRAWFIXED,
1001 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1002 ok(hwnd != NULL, "failed to create listview window\n");
1004 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
1005 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
1007 ok(r == 0, "should return zero\n");
1009 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
1010 ok(r == 0, "should return zero\n");
1012 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
1013 ok(r != 0, "got 0\n");
1015 /* returns dimensions */
1017 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
1018 ok(r == 0, "should be zero items\n");
1020 item.mask = LVIF_IMAGE | LVIF_TEXT;
1021 item.iItem = 0;
1022 item.iSubItem = 1;
1023 item.iImage = 0;
1024 item.pszText = 0;
1025 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1026 ok(r == -1, "should fail\n");
1028 item.iSubItem = 0;
1029 item.pszText = hello;
1030 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1031 ok(r == 0, "should not fail\n");
1033 SetRect(&r1, LVIR_ICON, 0, 0, 0);
1034 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
1035 expect(1, r);
1037 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1038 ok(r == TRUE, "should not fail\n");
1040 item.iSubItem = 0;
1041 item.pszText = hello;
1042 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1043 ok(r == 0, "should not fail\n");
1045 SetRect(&r2, LVIR_ICON, 0, 0, 0);
1046 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
1047 expect(1, r);
1049 ok(EqualRect(&r1, &r2), "rectangle should be the same\n");
1051 DestroyWindow(hwnd);
1053 /* I_IMAGECALLBACK set for item, try to get image with invalid subitem. */
1054 hwnd = create_listview_control(LVS_REPORT);
1055 ok(hwnd != NULL, "Failed to create listview.\n");
1057 memset(&item, 0, sizeof(item));
1058 item.mask = LVIF_IMAGE;
1059 item.iImage = I_IMAGECALLBACK;
1060 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1061 ok(!r, "Failed to insert item.\n");
1063 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1065 memset(&item, 0, sizeof(item));
1066 item.mask = LVIF_IMAGE;
1067 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1068 ok(r, "Failed to get item.\n");
1070 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, "get image dispinfo 1", FALSE);
1072 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1074 memset(&item, 0, sizeof(item));
1075 item.mask = LVIF_IMAGE;
1076 item.iSubItem = 1;
1077 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1078 ok(r, "Failed to get item.\n");
1080 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get image dispinfo 2", FALSE);
1082 DestroyWindow(hwnd);
1085 static void test_checkboxes(void)
1087 HWND hwnd;
1088 LVITEMA item;
1089 DWORD r;
1090 static CHAR text[] = "Text",
1091 text2[] = "Text2",
1092 text3[] = "Text3";
1094 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1095 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1096 ok(hwnd != NULL, "failed to create listview window\n");
1098 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
1099 item.mask = LVIF_TEXT | LVIF_STATE;
1100 item.stateMask = 0xffff;
1101 item.state = 0xfccc;
1102 item.iItem = 0;
1103 item.iSubItem = 0;
1104 item.pszText = text;
1105 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1106 expect(0, r);
1108 item.iItem = 0;
1109 item.mask = LVIF_STATE;
1110 item.stateMask = 0xffff;
1111 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1112 expect(1, r);
1113 ok(item.state == 0xfccc, "state %x\n", item.state);
1115 /* Don't set LVIF_STATE */
1116 item.mask = LVIF_TEXT;
1117 item.stateMask = 0xffff;
1118 item.state = 0xfccc;
1119 item.iItem = 1;
1120 item.iSubItem = 0;
1121 item.pszText = text;
1122 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1123 expect(1, r);
1125 item.iItem = 1;
1126 item.mask = LVIF_STATE;
1127 item.stateMask = 0xffff;
1128 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1129 expect(1, r);
1130 ok(item.state == 0, "state %x\n", item.state);
1132 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1133 expect(0, r);
1135 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
1136 item.iItem = 0;
1137 item.mask = LVIF_STATE;
1138 item.stateMask = 0xffff;
1139 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1140 expect(1, r);
1142 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
1143 item.iItem = 2;
1144 item.mask = LVIF_TEXT;
1145 item.state = 0;
1146 item.pszText = text2;
1147 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1148 expect(2, r);
1150 item.iItem = 2;
1151 item.mask = LVIF_STATE;
1152 item.stateMask = 0xffff;
1153 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1154 expect(1, r);
1155 ok(item.state == 0x1000, "state %x\n", item.state);
1157 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
1158 item.iItem = 3;
1159 item.mask = LVIF_TEXT | LVIF_STATE;
1160 item.stateMask = 0xffff;
1161 item.state = 0x2aaa;
1162 item.pszText = text3;
1163 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1164 expect(3, r);
1166 item.iItem = 3;
1167 item.mask = LVIF_STATE;
1168 item.stateMask = 0xffff;
1169 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1170 expect(1, r);
1171 ok(item.state == 0x1aaa, "state %x\n", item.state);
1173 /* Set an item's state to checked */
1174 item.iItem = 3;
1175 item.mask = LVIF_STATE;
1176 item.stateMask = 0xf000;
1177 item.state = 0x2000;
1178 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1179 expect(1, r);
1181 item.iItem = 3;
1182 item.mask = LVIF_STATE;
1183 item.stateMask = 0xffff;
1184 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1185 expect(1, r);
1186 ok(item.state == 0x2aaa, "state %x\n", item.state);
1188 /* Check that only the bits we asked for are returned,
1189 * and that all the others are set to zero
1191 item.iItem = 3;
1192 item.mask = LVIF_STATE;
1193 item.stateMask = 0xf000;
1194 item.state = 0xffff;
1195 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1196 expect(1, r);
1197 ok(item.state == 0x2000, "state %x\n", item.state);
1199 /* Set the style again and check that doesn't change an item's state */
1200 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1201 ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
1203 item.iItem = 3;
1204 item.mask = LVIF_STATE;
1205 item.stateMask = 0xffff;
1206 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1207 expect(1, r);
1208 ok(item.state == 0x2aaa, "state %x\n", item.state);
1210 /* Unsetting the checkbox extended style doesn't change an item's state */
1211 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1212 ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
1214 item.iItem = 3;
1215 item.mask = LVIF_STATE;
1216 item.stateMask = 0xffff;
1217 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1218 expect(1, r);
1219 ok(item.state == 0x2aaa, "state %x\n", item.state);
1221 /* Now setting the style again will change an item's state */
1222 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1223 expect(0, r);
1225 item.iItem = 3;
1226 item.mask = LVIF_STATE;
1227 item.stateMask = 0xffff;
1228 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1229 expect(1, r);
1230 ok(item.state == 0x1aaa, "state %x\n", item.state);
1232 /* Toggle checkbox tests (bug 9934) */
1233 memset (&item, 0xcc, sizeof(item));
1234 item.mask = LVIF_STATE;
1235 item.iItem = 3;
1236 item.iSubItem = 0;
1237 item.state = LVIS_FOCUSED;
1238 item.stateMask = LVIS_FOCUSED;
1239 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1240 expect(1, r);
1242 item.iItem = 3;
1243 item.mask = LVIF_STATE;
1244 item.stateMask = 0xffff;
1245 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1246 expect(1, r);
1247 ok(item.state == 0x1aab, "state %x\n", item.state);
1249 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1250 expect(0, r);
1251 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1252 expect(0, r);
1254 item.iItem = 3;
1255 item.mask = LVIF_STATE;
1256 item.stateMask = 0xffff;
1257 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1258 expect(1, r);
1259 ok(item.state == 0x2aab, "state %x\n", item.state);
1261 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1262 expect(0, r);
1263 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1264 expect(0, r);
1266 item.iItem = 3;
1267 item.mask = LVIF_STATE;
1268 item.stateMask = 0xffff;
1269 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1270 expect(1, r);
1271 ok(item.state == 0x1aab, "state %x\n", item.state);
1273 DestroyWindow(hwnd);
1276 static void insert_column(HWND hwnd, int idx)
1278 LVCOLUMNA column;
1279 INT rc;
1281 memset(&column, 0xcc, sizeof(column));
1282 column.mask = LVCF_SUBITEM;
1283 column.iSubItem = idx;
1285 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1286 expect(idx, rc);
1289 static void insert_item(HWND hwnd, int idx)
1291 static CHAR text[] = "foo";
1293 LVITEMA item;
1294 INT rc;
1296 memset(&item, 0xcc, sizeof (item));
1297 item.mask = LVIF_TEXT;
1298 item.iItem = idx;
1299 item.iSubItem = 0;
1300 item.pszText = text;
1302 rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1303 expect(idx, rc);
1306 static void test_items(void)
1308 const LPARAM lparamTest = 0x42;
1309 static CHAR text[] = "Text";
1310 char buffA[5];
1311 HWND hwnd;
1312 LVITEMA item;
1313 DWORD r;
1315 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1316 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1317 ok(hwnd != NULL, "failed to create listview window\n");
1320 * Test setting/getting item params
1323 /* Set up two columns */
1324 insert_column(hwnd, 0);
1325 insert_column(hwnd, 1);
1327 /* LVIS_SELECTED with zero stateMask */
1328 /* set */
1329 memset (&item, 0, sizeof (item));
1330 item.mask = LVIF_STATE;
1331 item.state = LVIS_SELECTED;
1332 item.stateMask = 0;
1333 item.iItem = 0;
1334 item.iSubItem = 0;
1335 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1336 expect(0, r);
1337 /* get */
1338 memset (&item, 0xcc, sizeof (item));
1339 item.mask = LVIF_STATE;
1340 item.stateMask = LVIS_SELECTED;
1341 item.state = 0;
1342 item.iItem = 0;
1343 item.iSubItem = 0;
1344 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1345 expect(1, r);
1346 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1347 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1348 ok(r, "got %ld\n", r);
1350 /* LVIS_SELECTED with zero stateMask */
1351 /* set */
1352 memset (&item, 0, sizeof (item));
1353 item.mask = LVIF_STATE;
1354 item.state = LVIS_FOCUSED;
1355 item.stateMask = 0;
1356 item.iItem = 0;
1357 item.iSubItem = 0;
1358 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1359 expect(0, r);
1360 /* get */
1361 memset (&item, 0xcc, sizeof (item));
1362 item.mask = LVIF_STATE;
1363 item.stateMask = LVIS_FOCUSED;
1364 item.state = 0;
1365 item.iItem = 0;
1366 item.iSubItem = 0;
1367 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1368 expect(1, r);
1369 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1370 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1371 ok(r, "got %ld\n", r);
1373 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1374 /* set */
1375 memset (&item, 0, sizeof (item));
1376 item.mask = LVIF_STATE;
1377 item.state = LVIS_CUT;
1378 item.stateMask = LVIS_FOCUSED;
1379 item.iItem = 0;
1380 item.iSubItem = 0;
1381 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1382 expect(0, r);
1383 /* get */
1384 memset (&item, 0xcc, sizeof (item));
1385 item.mask = LVIF_STATE;
1386 item.stateMask = LVIS_CUT;
1387 item.state = 0;
1388 item.iItem = 0;
1389 item.iSubItem = 0;
1390 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1391 expect(1, r);
1392 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1393 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1394 ok(r, "got %ld\n", r);
1396 /* Insert an item with just a param */
1397 memset (&item, 0xcc, sizeof (item));
1398 item.mask = LVIF_PARAM;
1399 item.iItem = 0;
1400 item.iSubItem = 0;
1401 item.lParam = lparamTest;
1402 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1403 expect(0, r);
1405 /* Test getting of the param */
1406 memset (&item, 0xcc, sizeof (item));
1407 item.mask = LVIF_PARAM;
1408 item.iItem = 0;
1409 item.iSubItem = 0;
1410 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1411 expect(1, r);
1412 ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1414 /* Set up a subitem */
1415 memset (&item, 0xcc, sizeof (item));
1416 item.mask = LVIF_TEXT;
1417 item.iItem = 0;
1418 item.iSubItem = 1;
1419 item.pszText = text;
1420 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1421 expect(1, r);
1423 item.mask = LVIF_TEXT;
1424 item.iItem = 0;
1425 item.iSubItem = 1;
1426 item.pszText = buffA;
1427 item.cchTextMax = sizeof(buffA);
1428 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1429 expect(1, r);
1430 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1432 /* set up with extra flag */
1433 /* 1. reset subitem text */
1434 item.mask = LVIF_TEXT;
1435 item.iItem = 0;
1436 item.iSubItem = 1;
1437 item.pszText = NULL;
1438 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1439 expect(1, r);
1441 item.mask = LVIF_TEXT;
1442 item.iItem = 0;
1443 item.iSubItem = 1;
1444 item.pszText = buffA;
1445 buffA[0] = 'a';
1446 item.cchTextMax = sizeof(buffA);
1447 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1448 expect(1, r);
1449 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1451 /* 2. set new text with extra flag specified */
1452 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1453 item.iItem = 0;
1454 item.iSubItem = 1;
1455 item.pszText = text;
1456 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1457 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %ld\n", r);
1459 if (r == 1)
1461 item.mask = LVIF_TEXT;
1462 item.iItem = 0;
1463 item.iSubItem = 1;
1464 item.pszText = buffA;
1465 buffA[0] = 'a';
1466 item.cchTextMax = sizeof(buffA);
1467 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1468 expect(1, r);
1469 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1472 /* Query param from subitem: returns main item param */
1473 memset (&item, 0xcc, sizeof (item));
1474 item.mask = LVIF_PARAM;
1475 item.iItem = 0;
1476 item.iSubItem = 1;
1477 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1478 expect(1, r);
1479 ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1481 /* Set up param on first subitem: no effect */
1482 memset (&item, 0xcc, sizeof (item));
1483 item.mask = LVIF_PARAM;
1484 item.iItem = 0;
1485 item.iSubItem = 1;
1486 item.lParam = lparamTest+1;
1487 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1488 expect(0, r);
1490 /* Query param from subitem again: should still return main item param */
1491 memset (&item, 0xcc, sizeof (item));
1492 item.mask = LVIF_PARAM;
1493 item.iItem = 0;
1494 item.iSubItem = 1;
1495 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1496 expect(1, r);
1497 ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1499 /**** Some tests of state highlighting ****/
1500 memset (&item, 0xcc, sizeof (item));
1501 item.mask = LVIF_STATE;
1502 item.iItem = 0;
1503 item.iSubItem = 0;
1504 item.state = LVIS_SELECTED;
1505 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1506 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1507 expect(1, r);
1508 item.iSubItem = 1;
1509 item.state = LVIS_DROPHILITED;
1510 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1511 expect(1, r);
1513 memset (&item, 0xcc, sizeof (item));
1514 item.mask = LVIF_STATE;
1515 item.iItem = 0;
1516 item.iSubItem = 0;
1517 item.stateMask = -1;
1518 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1519 expect(1, r);
1520 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1521 item.iSubItem = 1;
1522 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1523 expect(1, r);
1524 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1526 /* some notnull but meaningless masks */
1527 memset (&item, 0, sizeof(item));
1528 item.mask = LVIF_NORECOMPUTE;
1529 item.iItem = 0;
1530 item.iSubItem = 0;
1531 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1532 expect(1, r);
1533 memset (&item, 0, sizeof(item));
1534 item.mask = LVIF_DI_SETITEM;
1535 item.iItem = 0;
1536 item.iSubItem = 0;
1537 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1538 expect(1, r);
1540 /* set text to callback value already having it */
1541 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1542 expect(TRUE, r);
1543 memset (&item, 0, sizeof (item));
1544 item.mask = LVIF_TEXT;
1545 item.pszText = LPSTR_TEXTCALLBACKA;
1546 item.iItem = 0;
1547 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1548 expect(0, r);
1549 memset (&item, 0, sizeof (item));
1551 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1553 item.pszText = LPSTR_TEXTCALLBACKA;
1554 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1555 expect(TRUE, r);
1557 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1558 "check callback text comparison rule", FALSE);
1560 DestroyWindow(hwnd);
1563 static void test_columns(void)
1565 HWND hwnd, header;
1566 LVCOLUMNA column;
1567 LVITEMA item;
1568 INT order[2];
1569 CHAR buff[5];
1570 DWORD rc;
1572 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_LIST,
1573 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1574 ok(hwnd != NULL, "failed to create listview window\n");
1576 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1577 ok(header == NULL, "got %p\n", header);
1579 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1580 ok(rc == 0, "got %ld\n", rc);
1582 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1583 ok(header == NULL, "got %p\n", header);
1585 DestroyWindow(hwnd);
1587 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1588 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1589 ok(hwnd != NULL, "failed to create listview window\n");
1591 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, -1, 0);
1592 ok(!rc, "got %ld\n", rc);
1594 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, 0, 0);
1595 ok(!rc, "got %ld\n", rc);
1597 /* Add a column with no mask */
1598 memset(&column, 0xcc, sizeof(column));
1599 column.mask = 0;
1600 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1601 ok(rc == 0, "Inserting column with no mask failed with %ld\n", rc);
1603 /* Check its width */
1604 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1605 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %ld\n", rc);
1607 DestroyWindow(hwnd);
1609 /* LVM_GETCOLUMNORDERARRAY */
1610 hwnd = create_listview_control(LVS_REPORT);
1611 subclass_header(hwnd);
1613 memset(&column, 0, sizeof(column));
1614 column.mask = LVCF_WIDTH;
1615 column.cx = 100;
1616 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1617 expect(0, rc);
1619 column.cx = 200;
1620 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1621 expect(1, rc);
1623 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1625 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1626 expect(1, rc);
1627 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1628 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1630 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1631 expect(0, rc);
1633 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1635 /* LVM_SETCOLUMNORDERARRAY */
1636 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1638 order[0] = 0;
1639 order[1] = 1;
1640 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1641 expect(1, rc);
1643 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1644 expect(0, rc);
1646 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1648 /* after column added subitem is considered as present */
1649 insert_item(hwnd, 0);
1651 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1653 item.pszText = buff;
1654 item.cchTextMax = sizeof(buff);
1655 item.iItem = 0;
1656 item.iSubItem = 1;
1657 item.mask = LVIF_TEXT;
1658 memset(&g_itema, 0, sizeof(g_itema));
1659 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1660 expect(1, rc);
1661 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1663 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1664 "get subitem text after column added", FALSE);
1666 DestroyWindow(hwnd);
1668 /* Columns are not created right away. */
1669 hwnd = create_listview_control(LVS_REPORT);
1670 ok(hwnd != NULL, "Failed to create a listview window.\n");
1672 insert_item(hwnd, 0);
1674 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1675 ok(IsWindow(header), "Expected header handle.\n");
1676 rc = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
1677 ok(!rc, "Unexpected column count.\n");
1679 DestroyWindow(hwnd);
1682 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1683 static WNDPROC listviewWndProc;
1684 static HIMAGELIST test_create_imagelist;
1686 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1688 LRESULT ret;
1690 if (uMsg == WM_CREATE)
1692 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1693 lpcs->style |= LVS_REPORT;
1695 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1696 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1697 return ret;
1700 /* Header creation is delayed in classic implementation. */
1701 #define TEST_NO_HEADER(a) test_header_presence_(a, FALSE, __LINE__)
1702 #define TEST_HEADER_EXPECTED(a) test_header_presence_(a, TRUE, __LINE__)
1703 #define TEST_NO_HEADER2(a, b) test_header_presence_(a, b, __LINE__)
1704 static void test_header_presence_(HWND hwnd, BOOL present, int line)
1706 HWND header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1708 if (present)
1710 ok_(__FILE__, line)(IsWindow(header), "Header should have been created.\n");
1711 if (header) /* FIXME: remove when todo's are fixed */
1712 ok_(__FILE__, line)(header == GetDlgItem(hwnd, 0), "Dialog item expected.\n");
1714 else
1716 ok_(__FILE__, line)(!IsWindow(header), "Header shouldn't be created.\n");
1717 ok_(__FILE__, line)(NULL == GetDlgItem(hwnd, 0), "NULL dialog item expected.\n");
1721 static void test_create(BOOL is_version_6)
1723 char buff[16];
1724 HWND hList;
1725 HWND hHeader;
1726 LONG_PTR ret;
1727 LONG r;
1728 LVCOLUMNA col;
1729 RECT rect;
1730 WNDCLASSEXA cls;
1731 DWORD style;
1732 ATOM class;
1734 cls.cbSize = sizeof(WNDCLASSEXA);
1735 r = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
1736 ok(r, "Failed to get class info.\n");
1737 listviewWndProc = cls.lpfnWndProc;
1738 cls.lpfnWndProc = create_test_wndproc;
1739 cls.lpszClassName = "MyListView32";
1740 class = RegisterClassExA(&cls);
1741 ok(class, "Failed to register class.\n");
1743 test_create_imagelist = pImageList_Create(16, 16, 0, 5, 10);
1744 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1745 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1746 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1747 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1748 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1749 DestroyWindow(hList);
1751 /* header isn't created on LVS_ICON and LVS_LIST styles */
1752 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1753 TEST_NO_HEADER(hList);
1755 /* insert column */
1756 memset(&col, 0, sizeof(LVCOLUMNA));
1757 col.mask = LVCF_WIDTH;
1758 col.cx = 100;
1759 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1760 expect(0, r);
1761 TEST_HEADER_EXPECTED(hList);
1762 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1763 style = GetWindowLongA(hHeader, GWL_STYLE);
1764 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1765 DestroyWindow(hList);
1767 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1768 GetModuleHandleA(NULL), 0);
1769 TEST_NO_HEADER(hList);
1770 /* insert column */
1771 memset(&col, 0, sizeof(LVCOLUMNA));
1772 col.mask = LVCF_WIDTH;
1773 col.cx = 100;
1774 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1775 expect(0, r);
1776 TEST_HEADER_EXPECTED(hList);
1777 DestroyWindow(hList);
1779 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1780 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1781 GetModuleHandleA(NULL), 0);
1782 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1783 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1784 TEST_HEADER_EXPECTED(hList);
1785 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1786 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1787 TEST_HEADER_EXPECTED(hList);
1788 DestroyWindow(hList);
1790 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1791 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1792 GetModuleHandleA(NULL), 0);
1793 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1794 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1795 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1796 TEST_HEADER_EXPECTED(hList);
1797 ret = SetWindowLongPtrA(hList, GWL_STYLE, (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1798 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1799 TEST_HEADER_EXPECTED(hList);
1800 DestroyWindow(hList);
1802 /* LVS_REPORT without WS_VISIBLE */
1803 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1804 GetModuleHandleA(NULL), 0);
1805 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1806 todo_wine_if(is_version_6)
1807 TEST_NO_HEADER2(hList, is_version_6);
1809 /* insert column */
1810 memset(&col, 0, sizeof(LVCOLUMNA));
1811 col.mask = LVCF_WIDTH;
1812 col.cx = 100;
1813 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1814 expect(0, r);
1815 TEST_HEADER_EXPECTED(hList);
1816 DestroyWindow(hList);
1818 /* LVS_REPORT without WS_VISIBLE, try to show it */
1819 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1820 GetModuleHandleA(NULL), 0);
1821 todo_wine_if(is_version_6)
1822 TEST_NO_HEADER2(hList, is_version_6);
1824 ShowWindow(hList, SW_SHOW);
1825 TEST_HEADER_EXPECTED(hList);
1826 DestroyWindow(hList);
1828 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1829 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1830 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1831 TEST_HEADER_EXPECTED(hList);
1832 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1833 /* HDS_DRAGDROP set by default */
1834 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1835 DestroyWindow(hList);
1837 /* setting LVS_EX_HEADERDRAGDROP creates header */
1838 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1839 GetModuleHandleA(NULL), 0);
1840 todo_wine_if(is_version_6)
1841 TEST_NO_HEADER2(hList, is_version_6);
1843 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1844 TEST_HEADER_EXPECTED(hList);
1845 DestroyWindow(hList);
1847 /* setting LVS_EX_GRIDLINES creates header */
1848 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1849 GetModuleHandleA(NULL), 0);
1850 todo_wine_if(is_version_6)
1851 TEST_NO_HEADER2(hList, is_version_6);
1853 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1854 TEST_HEADER_EXPECTED(hList);
1855 DestroyWindow(hList);
1857 /* setting LVS_EX_FULLROWSELECT creates header */
1858 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1859 GetModuleHandleA(NULL), 0);
1860 todo_wine_if(is_version_6)
1861 TEST_NO_HEADER2(hList, is_version_6);
1862 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1863 TEST_HEADER_EXPECTED(hList);
1864 DestroyWindow(hList);
1866 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1867 hList = create_listview_control(LVS_ICON);
1868 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1869 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1870 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1871 DestroyWindow(hList);
1873 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1874 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1875 GetModuleHandleA(NULL), 0);
1876 todo_wine_if(is_version_6)
1877 TEST_NO_HEADER2(hList, is_version_6);
1879 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1880 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1881 ok(r == 1, "Unexpected ret value %ld.\n", r);
1882 /* right value contains garbage, probably because header columns are not set up */
1883 ok(rect.bottom >= 0, "Unexpected rectangle.\n");
1885 todo_wine_if(is_version_6)
1886 TEST_NO_HEADER2(hList, is_version_6);
1887 DestroyWindow(hList);
1889 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1890 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1891 hList = create_listview_control(LVS_OWNERDRAWFIXED | LVS_REPORT);
1892 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1893 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1894 DestroyWindow(hList);
1896 /* Test that window text is preserved. */
1897 hList = CreateWindowExA(0, WC_LISTVIEWA, "test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1898 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1899 ok(hList != NULL, "Failed to create ListView window.\n");
1900 *buff = 0;
1901 GetWindowTextA(hList, buff, sizeof(buff));
1902 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1903 DestroyWindow(hList);
1905 hList = CreateWindowExW(0, WC_LISTVIEWW, L"test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1906 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1907 ok(hList != NULL, "Failed to create ListView window.\n");
1908 *buff = 0;
1909 GetWindowTextA(hList, buff, sizeof(buff));
1910 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1911 DestroyWindow(hList);
1913 r = UnregisterClassA("MyListView32", NULL);
1914 ok(r, "Failed to unregister test class.\n");
1917 static void test_redraw(void)
1919 HWND hwnd;
1920 HDC hdc;
1921 BOOL res;
1922 DWORD r;
1923 RECT rect;
1925 hwnd = create_listview_control(LVS_REPORT);
1926 subclass_header(hwnd);
1928 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1930 InvalidateRect(hwnd, NULL, TRUE);
1931 UpdateWindow(hwnd);
1932 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1934 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1936 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1937 /* 1. Without backbuffer */
1938 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1939 expect(TRUE, res);
1941 hdc = GetWindowDC(hwndparent);
1943 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1944 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1945 ok(r == 1, "Expected not zero result\n");
1946 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1947 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1949 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1950 expect(TRUE, res);
1952 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1953 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1954 expect(1, r);
1955 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1956 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1958 /* 2. With backbuffer */
1959 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1960 LVS_EX_DOUBLEBUFFER);
1961 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1962 expect(TRUE, res);
1964 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1965 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1966 expect(1, r);
1967 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1968 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1970 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1971 expect(TRUE, res);
1973 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1974 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1975 todo_wine expect(1, r);
1976 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1977 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1979 ReleaseDC(hwndparent, hdc);
1981 /* test setting the window style to what it already was */
1982 UpdateWindow(hwnd);
1983 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE));
1984 GetUpdateRect(hwnd, &rect, FALSE);
1985 ok(rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0,
1986 "Expected empty update rect, got %s\n", wine_dbgstr_rect(&rect));
1988 DestroyWindow(hwnd);
1991 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1993 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1995 if(message == WM_NOTIFY) {
1996 NMHDR *nmhdr = (NMHDR*)lParam;
1997 if(nmhdr->code == NM_CUSTOMDRAW) {
1998 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1999 BOOL showsel_always = !!(GetWindowLongA(nmlvcd->nmcd.hdr.hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS);
2000 BOOL is_selected = !!(nmlvcd->nmcd.uItemState & CDIS_SELECTED);
2001 struct message msg;
2003 msg.message = message;
2004 msg.flags = sent|wparam|lparam|custdraw;
2005 msg.wParam = wParam;
2006 msg.lParam = lParam;
2007 msg.id = nmhdr->code;
2008 msg.stage = nmlvcd->nmcd.dwDrawStage;
2009 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
2011 switch(nmlvcd->nmcd.dwDrawStage) {
2012 case CDDS_PREPAINT:
2013 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
2014 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
2015 case CDDS_ITEMPREPAINT:
2016 clr = GetBkColor(nmlvcd->nmcd.hdc);
2017 todo_wine_if(nmlvcd->iSubItem)
2018 ok(clr == c0ffee, "Unexpected background color %#lx.\n", clr);
2019 nmlvcd->clrTextBk = CLR_DEFAULT;
2020 nmlvcd->clrText = RGB(0, 255, 0);
2021 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
2022 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
2023 clr = GetBkColor(nmlvcd->nmcd.hdc);
2024 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "Unexpected text background %#lx.\n", nmlvcd->clrTextBk);
2025 ok(nmlvcd->clrText == RGB(0, 255, 0), "Unexpected text color %#lx.\n", nmlvcd->clrText);
2026 if (showsel_always && is_selected && nmlvcd->iSubItem)
2027 ok(clr == GetSysColor(COLOR_3DFACE), "Unexpected background color %#lx.\n", clr);
2028 else
2029 todo_wine_if(nmlvcd->iSubItem)
2030 ok(clr == c0ffee, "clr=%.8lx\n", clr);
2031 return CDRF_NOTIFYPOSTPAINT;
2032 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
2033 clr = GetBkColor(nmlvcd->nmcd.hdc);
2034 if (showsel_always && is_selected)
2035 ok(clr == GetSysColor(COLOR_3DFACE), "Unexpected background color %#lx.\n", clr);
2036 else
2038 todo_wine
2039 ok(clr == c0ffee, "Unexpected background color %#lx.\n", clr);
2042 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "Unexpected text background color %#lx.\n", nmlvcd->clrTextBk);
2043 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%lx\n", nmlvcd->clrText);
2044 return CDRF_DODEFAULT;
2046 return CDRF_DODEFAULT;
2050 return DefWindowProcA(hwnd, message, wParam, lParam);
2053 static void test_customdraw(void)
2055 HWND hwnd;
2056 WNDPROC oldwndproc;
2057 LVITEMA item;
2059 hwnd = create_listview_control(LVS_REPORT);
2061 insert_column(hwnd, 0);
2062 insert_column(hwnd, 1);
2063 insert_item(hwnd, 0);
2065 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
2066 (LONG_PTR)cd_wndproc);
2068 InvalidateRect(hwnd, NULL, TRUE);
2069 UpdateWindow(hwnd);
2071 /* message tests */
2072 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2073 InvalidateRect(hwnd, NULL, TRUE);
2074 UpdateWindow(hwnd);
2075 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
2077 /* Check colors when item is selected. */
2078 item.mask = LVIF_STATE;
2079 item.stateMask = LVIS_SELECTED;
2080 item.state = LVIS_SELECTED;
2081 SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2083 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2084 InvalidateRect(hwnd, NULL, TRUE);
2085 UpdateWindow(hwnd);
2086 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq,
2087 "parent customdraw, item selected, LVS_REPORT, selection", FALSE);
2089 SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) | LVS_SHOWSELALWAYS);
2090 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2091 InvalidateRect(hwnd, NULL, TRUE);
2092 UpdateWindow(hwnd);
2093 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq,
2094 "parent customdraw, item selected, LVS_SHOWSELALWAYS, LVS_REPORT", FALSE);
2096 DestroyWindow(hwnd);
2098 hwnd = create_listview_control(LVS_LIST);
2100 insert_column(hwnd, 0);
2101 insert_column(hwnd, 1);
2102 insert_item(hwnd, 0);
2104 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2105 InvalidateRect(hwnd, NULL, TRUE);
2106 UpdateWindow(hwnd);
2107 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
2109 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
2110 DestroyWindow(hwnd);
2113 static void test_icon_spacing(void)
2115 /* LVM_SETICONSPACING */
2116 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
2118 HWND hwnd;
2119 WORD w, h;
2120 INT r;
2122 hwnd = create_listview_control(LVS_ICON);
2123 ok(hwnd != NULL, "failed to create a listview window\n");
2125 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
2126 expect(NFR_ANSI, r);
2128 /* reset the icon spacing to defaults */
2129 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
2131 /* now we can request what the defaults are */
2132 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
2133 w = LOWORD(r);
2134 h = HIWORD(r);
2136 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2138 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
2139 ok(r == MAKELONG(w, h) ||
2140 broken(r == MAKELONG(w, w)), /* win98 */
2141 "Expected %ld, got %d\n", MAKELONG(w, h), r);
2143 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
2144 expect(MAKELONG(20,30), r);
2146 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
2147 expect(MAKELONG(25,35), r);
2149 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
2151 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2152 DestroyWindow(hwnd);
2155 static void test_color(void)
2157 RECT rect;
2158 HWND hwnd;
2159 DWORD r;
2160 int i;
2162 COLORREF color;
2163 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
2165 hwnd = create_listview_control(LVS_REPORT);
2166 ok(hwnd != NULL, "failed to create a listview window\n");
2168 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2170 for (i = 0; i < 4; i++)
2172 color = colors[i];
2174 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
2175 expect(TRUE, r);
2176 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
2177 expect(color, r);
2179 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
2180 expect (TRUE, r);
2181 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
2182 expect(color, r);
2184 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
2185 expect(TRUE, r);
2186 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
2187 expect(color, r);
2190 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
2191 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2193 /* invalidation test done separately to avoid a message chain mess */
2194 r = ValidateRect(hwnd, NULL);
2195 expect(TRUE, r);
2196 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
2197 expect(TRUE, r);
2199 rect.right = rect.bottom = 1;
2200 r = GetUpdateRect(hwnd, &rect, TRUE);
2201 todo_wine expect(FALSE, r);
2202 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2204 r = ValidateRect(hwnd, NULL);
2205 expect(TRUE, r);
2206 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
2207 expect(TRUE, r);
2209 rect.right = rect.bottom = 1;
2210 r = GetUpdateRect(hwnd, &rect, TRUE);
2211 todo_wine expect(FALSE, r);
2212 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2214 r = ValidateRect(hwnd, NULL);
2215 expect(TRUE, r);
2216 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2217 expect(TRUE, r);
2219 rect.right = rect.bottom = 1;
2220 r = GetUpdateRect(hwnd, &rect, TRUE);
2221 todo_wine expect(FALSE, r);
2222 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2224 DestroyWindow(hwnd);
2227 static void test_item_count(void)
2229 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2231 HWND hwnd;
2232 DWORD r;
2233 HDC hdc;
2234 HFONT hOldFont;
2235 TEXTMETRICA tm;
2236 RECT rect;
2237 INT height;
2239 LVITEMA item0;
2240 LVITEMA item1;
2241 LVITEMA item2;
2242 static CHAR item0text[] = "item0";
2243 static CHAR item1text[] = "item1";
2244 static CHAR item2text[] = "item2";
2246 hwnd = create_listview_control(LVS_REPORT);
2247 ok(hwnd != NULL, "failed to create a listview window\n");
2249 /* resize in dpiaware manner to fit all 3 items added */
2250 hdc = GetDC(0);
2251 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2252 GetTextMetricsA(hdc, &tm);
2253 /* 2 extra pixels for bounds and header border */
2254 height = tm.tmHeight + 2;
2255 SelectObject(hdc, hOldFont);
2256 ReleaseDC(0, hdc);
2258 GetWindowRect(hwnd, &rect);
2259 /* 3 items + 1 header + 1 to be sure */
2260 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2262 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2264 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2265 expect(0, r);
2267 /* [item0] */
2268 item0.mask = LVIF_TEXT;
2269 item0.iItem = 0;
2270 item0.iSubItem = 0;
2271 item0.pszText = item0text;
2272 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2273 expect(0, r);
2275 /* [item0, item1] */
2276 item1.mask = LVIF_TEXT;
2277 item1.iItem = 1;
2278 item1.iSubItem = 0;
2279 item1.pszText = item1text;
2280 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2281 expect(1, r);
2283 /* [item0, item1, item2] */
2284 item2.mask = LVIF_TEXT;
2285 item2.iItem = 2;
2286 item2.iSubItem = 0;
2287 item2.pszText = item2text;
2288 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2289 expect(2, r);
2291 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2292 expect(3, r);
2294 /* [item0, item1] */
2295 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2296 expect(TRUE, r);
2298 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2299 expect(2, r);
2301 /* [] */
2302 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2303 expect(TRUE, r);
2305 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2306 expect(0, r);
2308 /* [item0] */
2309 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2310 expect(0, r);
2312 /* [item0, item1] */
2313 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2314 expect(1, r);
2316 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2317 expect(2, r);
2319 /* [item0, item1, item2] */
2320 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2321 expect(2, r);
2323 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2324 expect(3, r);
2326 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2328 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2329 DestroyWindow(hwnd);
2332 static void test_item_position(void)
2334 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2336 HWND hwnd;
2337 DWORD r;
2338 POINT position;
2340 LVITEMA item0;
2341 LVITEMA item1;
2342 LVITEMA item2;
2343 static CHAR item0text[] = "item0";
2344 static CHAR item1text[] = "item1";
2345 static CHAR item2text[] = "item2";
2347 hwnd = create_listview_control(LVS_ICON);
2348 ok(hwnd != NULL, "failed to create a listview window\n");
2350 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2352 /* [item0] */
2353 item0.mask = LVIF_TEXT;
2354 item0.iItem = 0;
2355 item0.iSubItem = 0;
2356 item0.pszText = item0text;
2357 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2358 expect(0, r);
2360 /* [item0, item1] */
2361 item1.mask = LVIF_TEXT;
2362 item1.iItem = 1;
2363 item1.iSubItem = 0;
2364 item1.pszText = item1text;
2365 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2366 expect(1, r);
2368 /* [item0, item1, item2] */
2369 item2.mask = LVIF_TEXT;
2370 item2.iItem = 2;
2371 item2.iSubItem = 0;
2372 item2.pszText = item2text;
2373 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2374 expect(2, r);
2376 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2377 expect(TRUE, r);
2378 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2379 expect(TRUE, r);
2380 expect2(10, 5, position.x, position.y);
2382 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2383 expect(TRUE, r);
2384 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2385 expect(TRUE, r);
2386 expect2(0, 0, position.x, position.y);
2388 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2389 expect(TRUE, r);
2390 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2391 expect(TRUE, r);
2392 expect2(20, 20, position.x, position.y);
2394 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2396 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2397 DestroyWindow(hwnd);
2400 static void test_getorigin(void)
2402 /* LVM_GETORIGIN */
2404 HWND hwnd;
2405 DWORD r;
2406 POINT position;
2408 position.x = position.y = 0;
2410 hwnd = create_listview_control(LVS_ICON);
2411 ok(hwnd != NULL, "failed to create a listview window\n");
2412 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2414 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2415 expect(TRUE, r);
2416 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2417 DestroyWindow(hwnd);
2419 hwnd = create_listview_control(LVS_SMALLICON);
2420 ok(hwnd != NULL, "failed to create a listview window\n");
2421 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2423 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2424 expect(TRUE, r);
2425 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2426 DestroyWindow(hwnd);
2428 hwnd = create_listview_control(LVS_LIST);
2429 ok(hwnd != NULL, "failed to create a listview window\n");
2430 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2432 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2433 expect(FALSE, r);
2434 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2435 DestroyWindow(hwnd);
2437 hwnd = create_listview_control(LVS_REPORT);
2438 ok(hwnd != NULL, "failed to create a listview window\n");
2439 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2441 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2442 expect(FALSE, r);
2443 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2444 DestroyWindow(hwnd);
2447 static void test_multiselect(void)
2449 typedef struct t_select_task
2451 const char *descr;
2452 int initPos;
2453 int loopVK;
2454 int count;
2455 int result;
2456 } select_task;
2458 HWND hwnd;
2459 INT r;
2460 int i, j;
2461 static const int items=5;
2462 DWORD item_count;
2463 select_task task;
2464 LONG_PTR style;
2465 LVITEMA item;
2467 static struct t_select_task task_list[] = {
2468 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2469 { "using VK_UP", -1, VK_UP, -1, -1 },
2470 { "using VK_END", 0, VK_END, 1, -1 },
2471 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2474 hwnd = create_listview_control(LVS_REPORT);
2476 for (i = 0; i < items; i++)
2477 insert_item(hwnd, 0);
2479 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2480 expect(items, item_count);
2482 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2483 ok(r == -1, "got %d\n", r);
2485 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2486 ok(r == -1, "got %d\n", r);
2488 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2489 ok(r == 0, "got %d\n", r);
2491 /* out of range index */
2492 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, items);
2493 ok(r == 0, "got %d\n", r);
2495 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2496 ok(r == 0, "got %d\n", r);
2498 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -2);
2499 ok(r == 0, "got %d\n", r);
2501 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2502 ok(r == 0, "got %d\n", r);
2504 for (i = 0; i < ARRAY_SIZE(task_list); i++) {
2505 DWORD selected_count;
2506 LVITEMA item;
2508 task = task_list[i];
2510 /* deselect all items */
2511 item.state = 0;
2512 item.stateMask = LVIS_SELECTED;
2513 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2514 ok(r, "got %d\n", r);
2515 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2517 /* set initial position */
2518 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2519 ok(r, "got %d\n", r);
2521 item.state = LVIS_SELECTED;
2522 item.stateMask = LVIS_SELECTED;
2523 r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2524 ok(r, "got %d\n", r);
2526 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2527 ok(selected_count == 1, "expected 1, got %ld\n", selected_count);
2529 hold_key(VK_SHIFT);
2531 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2532 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2533 expect(0,r);
2534 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2535 expect(0,r);
2538 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2540 ok((task.result == -1 ? item_count : task.result) == selected_count,
2541 "Failed multiple selection %s. There should be %ld selected items (is %ld)\n",
2542 task.descr, item_count, selected_count);
2544 release_key(VK_SHIFT);
2546 DestroyWindow(hwnd);
2548 /* make multiple selection, then switch to LVS_SINGLESEL */
2549 hwnd = create_listview_control(LVS_REPORT);
2550 for (i=0;i<items;i++) {
2551 insert_item(hwnd, 0);
2553 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2554 expect(items,item_count);
2556 /* try with NULL pointer */
2557 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2558 expect(FALSE, r);
2560 /* select all, check notifications */
2561 item.state = 0;
2562 item.stateMask = LVIS_SELECTED;
2563 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2564 ok(r, "got %d\n", r);
2566 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2568 item.stateMask = LVIS_SELECTED;
2569 item.state = LVIS_SELECTED;
2570 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2571 expect(TRUE, r);
2573 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2574 "select all notification", FALSE);
2576 /* select all again (all selected already) */
2577 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2579 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2581 item.stateMask = LVIS_SELECTED;
2582 item.state = LVIS_SELECTED;
2583 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2584 expect(TRUE, r);
2586 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2587 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2588 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2590 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2591 "select all notification 2", FALSE);
2593 /* deselect all items */
2594 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2596 item.state = 0;
2597 item.stateMask = LVIS_SELECTED;
2598 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2599 ok(r, "got %d\n", r);
2601 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2602 "deselect all notification", FALSE);
2604 /* deselect all items again */
2605 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2606 item.state = 0;
2607 item.stateMask = LVIS_SELECTED;
2608 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2609 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2611 /* any non-zero state value does the same */
2612 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2614 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2616 item.stateMask = LVIS_SELECTED;
2617 item.state = LVIS_CUT;
2618 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2619 expect(TRUE, r);
2621 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2622 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2623 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2625 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2626 "set state all notification 3", FALSE);
2628 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2629 ok(r, "got %d\n", r);
2630 for (i = 0; i < 3; i++) {
2631 item.state = LVIS_SELECTED;
2632 item.stateMask = LVIS_SELECTED;
2633 r = SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2634 ok(r, "got %d\n", r);
2637 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2638 expect(3, r);
2639 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2640 expect(-1, r);
2642 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2643 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2644 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2645 /* check that style is accepted */
2646 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2647 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2649 for (i=0;i<3;i++) {
2650 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2651 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2653 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2654 expect(3, r);
2655 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2656 ok(r == -1, "got %d\n", r);
2658 /* select one more */
2659 item.state = LVIS_SELECTED;
2660 item.stateMask = LVIS_SELECTED;
2661 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2662 ok(r, "got %d\n", r);
2664 for (i=0;i<3;i++) {
2665 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2666 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2669 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2670 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2672 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2673 expect(1, r);
2674 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2675 expect(-1, r);
2677 /* try to select all on LVS_SINGLESEL */
2678 memset(&item, 0, sizeof(item));
2679 item.stateMask = LVIS_SELECTED;
2680 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2681 expect(TRUE, r);
2682 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2683 ok(r == -1, "got %d\n", r);
2685 item.stateMask = LVIS_SELECTED;
2686 item.state = LVIS_SELECTED;
2687 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2688 expect(FALSE, r);
2690 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2691 expect(0, r);
2692 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2693 expect(-1, r);
2695 /* try to deselect all on LVS_SINGLESEL */
2696 item.stateMask = LVIS_SELECTED;
2697 item.state = LVIS_SELECTED;
2698 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2699 expect(TRUE, r);
2701 item.stateMask = LVIS_SELECTED;
2702 item.state = 0;
2703 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2704 expect(TRUE, r);
2705 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2706 expect(0, r);
2708 /* 1. selection mark is update when new focused item is set */
2709 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2710 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2712 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2713 expect(-1, r);
2715 item.stateMask = LVIS_FOCUSED;
2716 item.state = LVIS_FOCUSED;
2717 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2718 expect(TRUE, r);
2720 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2721 expect(0, r);
2723 /* it's not updated if already set */
2724 item.stateMask = LVIS_FOCUSED;
2725 item.state = LVIS_FOCUSED;
2726 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2727 expect(TRUE, r);
2729 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2730 expect(0, r);
2732 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2733 expect(0, r);
2735 item.stateMask = LVIS_FOCUSED;
2736 item.state = LVIS_FOCUSED;
2737 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2738 expect(TRUE, r);
2740 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2741 expect(-1, r);
2743 /* need to reset focused item first */
2744 item.stateMask = LVIS_FOCUSED;
2745 item.state = 0;
2746 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2747 expect(TRUE, r);
2749 item.stateMask = LVIS_FOCUSED;
2750 item.state = LVIS_FOCUSED;
2751 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2752 expect(TRUE, r);
2754 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2755 expect(2, r);
2757 item.stateMask = LVIS_FOCUSED;
2758 item.state = 0;
2759 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2760 expect(TRUE, r);
2762 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2763 expect(2, r);
2765 /* 2. same tests, with LVM_SETITEM */
2766 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2767 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2769 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2770 expect(2, r);
2772 item.stateMask = LVIS_FOCUSED;
2773 item.state = LVIS_FOCUSED;
2774 item.mask = LVIF_STATE;
2775 item.iItem = item.iSubItem = 0;
2776 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2777 expect(TRUE, r);
2779 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2780 expect(0, r);
2782 /* it's not updated if already set */
2783 item.stateMask = LVIS_FOCUSED;
2784 item.state = LVIS_FOCUSED;
2785 item.mask = LVIF_STATE;
2786 item.iItem = 1;
2787 item.iSubItem = 0;
2788 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2789 expect(TRUE, r);
2791 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2792 expect(0, r);
2794 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2795 expect(0, r);
2797 item.stateMask = LVIS_FOCUSED;
2798 item.state = LVIS_FOCUSED;
2799 item.mask = LVIF_STATE;
2800 item.iItem = 1;
2801 item.iSubItem = 0;
2802 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2803 expect(TRUE, r);
2805 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2806 expect(-1, r);
2808 /* need to reset focused item first */
2809 item.stateMask = LVIS_FOCUSED;
2810 item.state = 0;
2811 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2812 expect(TRUE, r);
2814 item.stateMask = LVIS_FOCUSED;
2815 item.state = LVIS_FOCUSED;
2816 item.mask = LVIF_STATE;
2817 item.iItem = 2;
2818 item.iSubItem = 0;
2819 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2820 expect(TRUE, r);
2822 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2823 expect(2, r);
2825 item.stateMask = LVIS_FOCUSED;
2826 item.state = 0;
2827 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2828 expect(TRUE, r);
2830 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2831 expect(2, r);
2833 DestroyWindow(hwnd);
2836 static void test_subitem_rect(void)
2838 HWND hwnd;
2839 DWORD r;
2840 LVCOLUMNA col;
2841 RECT rect, rect2;
2842 INT arr[3];
2844 /* test LVM_GETSUBITEMRECT for header */
2845 hwnd = create_listview_control(LVS_REPORT);
2846 ok(hwnd != NULL, "failed to create a listview window\n");
2847 /* add some columns */
2848 memset(&col, 0, sizeof(LVCOLUMNA));
2849 col.mask = LVCF_WIDTH;
2850 col.cx = 100;
2851 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2852 expect(0, r);
2853 col.cx = 150;
2854 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2855 expect(1, r);
2856 col.cx = 200;
2857 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2858 expect(2, r);
2859 /* item = -1 means header, subitem index is 1 based */
2860 SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2861 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2862 expect(0, r);
2864 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2865 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2866 expect(1, r);
2868 expect(100, rect.left);
2869 expect(250, rect.right);
2870 expect(3, rect.top);
2872 SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2873 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2874 expect(1, r);
2876 expect(250, rect.left);
2877 expect(450, rect.right);
2878 expect(3, rect.top);
2880 /* item LVS_REPORT padding isn't applied to subitems */
2881 insert_item(hwnd, 0);
2883 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2884 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2885 expect(1, r);
2886 expect(100, rect.left);
2887 expect(250, rect.right);
2889 SetRect(&rect, LVIR_ICON, 1, 0, 0);
2890 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2891 expect(1, r);
2892 /* no icon attached - zero width rectangle, with no left padding */
2893 expect(100, rect.left);
2894 expect(100, rect.right);
2896 SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2897 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2898 expect(1, r);
2899 /* same as full LVIR_BOUNDS */
2900 expect(100, rect.left);
2901 expect(250, rect.right);
2903 r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2904 ok(r, "got %ld\n", r);
2906 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2907 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2908 expect(1, r);
2909 expect(90, rect.left);
2910 expect(240, rect.right);
2912 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2914 /* test header interaction */
2915 subclass_header(hwnd);
2916 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2918 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2919 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2920 expect(1, r);
2922 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2923 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2924 expect(1, r);
2926 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2927 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2928 expect(1, r);
2930 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2931 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2932 expect(1, r);
2934 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2936 DestroyWindow(hwnd);
2938 /* test subitem rects after re-arranging columns */
2939 hwnd = create_listview_control(LVS_REPORT);
2940 ok(hwnd != NULL, "failed to create a listview window\n");
2941 memset(&col, 0, sizeof(LVCOLUMNA));
2942 col.mask = LVCF_WIDTH;
2944 col.cx = 100;
2945 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2946 expect(0, r);
2948 col.cx = 200;
2949 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2950 expect(1, r);
2952 col.cx = 300;
2953 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2954 expect(2, r);
2956 insert_item(hwnd, 0);
2957 insert_item(hwnd, 1);
2959 /* wrong item is refused for main item */
2960 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2961 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2962 expect(FALSE, r);
2964 /* for subitems rectangle is calculated even if there's no item added */
2965 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2966 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2967 expect(TRUE, r);
2969 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2970 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2971 expect(TRUE, r);
2972 expect(rect.right, rect2.right);
2973 expect(rect.left, rect2.left);
2974 expect(rect.bottom, rect2.top);
2975 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2977 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2978 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2979 expect(TRUE, r);
2981 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2982 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2983 expect(TRUE, r);
2984 expect(0, rect.left);
2985 expect(600, rect.right);
2987 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2988 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2989 expect(TRUE, r);
2990 expect(0, rect.left);
2991 expect(200, rect.right);
2993 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2994 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
2995 expect(TRUE, r);
2996 expect(0, rect2.left);
2997 expect(200, rect2.right);
2998 /* items are of the same height */
2999 ok(rect2.top > 0, "expected positive item height\n");
3000 expect(rect.bottom, rect2.top);
3001 expect(rect.bottom * 2 - rect.top, rect2.bottom);
3003 SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
3004 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
3005 expect(TRUE, r);
3006 expect(300, rect.left);
3007 expect(600, rect.right);
3009 DestroyWindow(hwnd);
3011 /* try it for non LVS_REPORT style */
3012 hwnd = CreateWindowA(WC_LISTVIEWA, "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
3013 GetModuleHandleA(NULL), 0);
3014 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
3015 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
3016 expect(0, r);
3017 /* rect is unchanged */
3018 expect(0, rect.left);
3019 expect(-10, rect.right);
3020 expect(1, rect.top);
3021 expect(-10, rect.bottom);
3022 DestroyWindow(hwnd);
3025 /* comparison callback for test_sorting */
3026 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
3028 if (first == second) return 0;
3029 return (first > second ? 1 : -1);
3032 static void test_sorting(void)
3034 HWND hwnd;
3035 LVITEMA item = {0};
3036 INT r;
3037 LONG_PTR style;
3038 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
3039 CHAR buff[10];
3041 hwnd = create_listview_control(LVS_REPORT);
3042 ok(hwnd != NULL, "failed to create a listview window\n");
3044 /* insert some items */
3045 item.mask = LVIF_PARAM | LVIF_STATE;
3046 item.state = LVIS_SELECTED;
3047 item.iItem = 0;
3048 item.iSubItem = 0;
3049 item.lParam = 3;
3050 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3051 expect(0, r);
3053 item.mask = LVIF_PARAM;
3054 item.iItem = 1;
3055 item.iSubItem = 0;
3056 item.lParam = 2;
3057 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3058 expect(1, r);
3060 item.mask = LVIF_STATE | LVIF_PARAM;
3061 item.state = LVIS_SELECTED;
3062 item.iItem = 2;
3063 item.iSubItem = 0;
3064 item.lParam = 4;
3065 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3066 expect(2, r);
3068 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
3069 expect(-1, r);
3071 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3072 expect(2, r);
3074 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
3075 expect(TRUE, r);
3077 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3078 expect(2, r);
3079 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
3080 expect(-1, r);
3081 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
3082 expect(0, r);
3083 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
3084 expect(LVIS_SELECTED, r);
3085 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
3086 expect(LVIS_SELECTED, r);
3088 DestroyWindow(hwnd);
3090 /* switch to LVS_SORTASCENDING when some items added */
3091 hwnd = create_listview_control(LVS_REPORT);
3092 ok(hwnd != NULL, "failed to create a listview window\n");
3094 item.mask = LVIF_TEXT;
3095 item.iItem = 0;
3096 item.iSubItem = 0;
3097 item.pszText = names[1];
3098 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3099 expect(0, r);
3101 item.mask = LVIF_TEXT;
3102 item.iItem = 1;
3103 item.iSubItem = 0;
3104 item.pszText = names[2];
3105 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3106 expect(1, r);
3108 item.mask = LVIF_TEXT;
3109 item.iItem = 2;
3110 item.iSubItem = 0;
3111 item.pszText = names[0];
3112 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3113 expect(2, r);
3115 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3116 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3117 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3118 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3120 /* no sorting performed when switched to LVS_SORTASCENDING */
3121 item.mask = LVIF_TEXT;
3122 item.iItem = 0;
3123 item.pszText = buff;
3124 item.cchTextMax = sizeof(buff);
3125 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3126 expect(TRUE, r);
3127 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3129 item.iItem = 1;
3130 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3131 expect(TRUE, r);
3132 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3134 item.iItem = 2;
3135 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3136 expect(TRUE, r);
3137 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3139 /* adding new item doesn't resort list */
3140 item.mask = LVIF_TEXT;
3141 item.iItem = 3;
3142 item.iSubItem = 0;
3143 item.pszText = names[3];
3144 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3145 expect(3, r);
3147 item.mask = LVIF_TEXT;
3148 item.iItem = 0;
3149 item.pszText = buff;
3150 item.cchTextMax = sizeof(buff);
3151 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3152 expect(TRUE, r);
3153 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3155 item.iItem = 1;
3156 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3157 expect(TRUE, r);
3158 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3160 item.iItem = 2;
3161 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3162 expect(TRUE, r);
3163 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3165 item.iItem = 3;
3166 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3167 expect(TRUE, r);
3168 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3170 /* corner case - item should be placed at first position */
3171 item.mask = LVIF_TEXT;
3172 item.iItem = 4;
3173 item.iSubItem = 0;
3174 item.pszText = names[4];
3175 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3176 expect(0, r);
3178 item.iItem = 0;
3179 item.pszText = buff;
3180 item.cchTextMax = sizeof(buff);
3181 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3182 expect(TRUE, r);
3183 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
3185 item.iItem = 1;
3186 item.pszText = buff;
3187 item.cchTextMax = sizeof(buff);
3188 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3189 expect(TRUE, r);
3190 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3192 item.iItem = 2;
3193 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3194 expect(TRUE, r);
3195 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3197 item.iItem = 3;
3198 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3199 expect(TRUE, r);
3200 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3202 item.iItem = 4;
3203 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3204 expect(TRUE, r);
3205 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3207 DestroyWindow(hwnd);
3210 static void test_ownerdata(void)
3212 static char test_str[] = "test";
3214 HWND hwnd;
3215 LONG_PTR style, ret;
3216 DWORD res;
3217 LVITEMA item;
3219 /* Setting LVS_OWNERDATA after creation leads to crash on older versions < 5.80 */
3220 hwnd = create_listview_control(LVS_REPORT);
3221 ok(hwnd != NULL, "failed to create a listview window\n");
3222 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3223 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3225 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3227 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3228 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3229 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3230 "try to switch to LVS_OWNERDATA seq", FALSE);
3232 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3233 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3234 DestroyWindow(hwnd);
3236 /* try to set LVS_OWNERDATA after creation just having it */
3237 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3238 ok(hwnd != NULL, "failed to create a listview window\n");
3239 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3240 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3242 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3244 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3245 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3246 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3247 "try to switch to LVS_OWNERDATA seq", FALSE);
3248 DestroyWindow(hwnd);
3250 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3251 ok(hwnd != NULL, "failed to create a listview window\n");
3252 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3253 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3255 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3257 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3258 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3259 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3260 "try to switch to LVS_OWNERDATA seq", FALSE);
3261 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3262 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3263 DestroyWindow(hwnd);
3265 /* try select an item */
3266 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3267 ok(hwnd != NULL, "failed to create a listview window\n");
3268 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3269 expect(1, res);
3270 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3271 expect(0, res);
3272 memset(&item, 0, sizeof(item));
3273 item.stateMask = LVIS_SELECTED;
3274 item.state = LVIS_SELECTED;
3275 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3276 expect(TRUE, res);
3277 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3278 expect(1, res);
3279 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3280 expect(1, res);
3281 DestroyWindow(hwnd);
3283 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3284 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3285 ok(hwnd != NULL, "failed to create a listview window\n");
3286 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3287 expect(1, res);
3288 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3289 expect(1, res);
3290 memset(&item, 0, sizeof(item));
3291 item.mask = LVIF_STATE;
3292 item.iItem = 0;
3293 item.stateMask = LVIS_SELECTED;
3294 item.state = LVIS_SELECTED;
3295 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3296 expect(FALSE, res);
3297 memset(&item, 0, sizeof(item));
3298 item.pszText = test_str;
3299 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3300 expect(FALSE, res);
3301 DestroyWindow(hwnd);
3303 /* check notifications after focused/selected changed */
3304 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3305 ok(hwnd != NULL, "failed to create a listview window\n");
3306 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3307 expect(1, res);
3309 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3311 memset(&item, 0, sizeof(item));
3312 item.stateMask = LVIS_SELECTED;
3313 item.state = LVIS_SELECTED;
3314 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3315 expect(TRUE, res);
3317 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3318 "ownerdata select notification", TRUE);
3320 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3322 memset(&item, 0, sizeof(item));
3323 item.stateMask = LVIS_FOCUSED;
3324 item.state = LVIS_FOCUSED;
3325 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3326 expect(TRUE, res);
3328 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3329 "ownerdata focus notification", TRUE);
3331 /* select all, check notifications */
3332 item.stateMask = LVIS_SELECTED;
3333 item.state = 0;
3334 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3335 expect(TRUE, res);
3337 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3339 item.stateMask = LVIS_SELECTED;
3340 item.state = LVIS_SELECTED;
3342 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3343 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3344 expect(TRUE, res);
3345 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3346 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3347 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3348 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3349 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3350 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3351 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3353 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3354 "ownerdata select all notification", FALSE);
3356 /* select all again, note that all items are selected already */
3357 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3358 item.stateMask = LVIS_SELECTED;
3359 item.state = LVIS_SELECTED;
3361 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3362 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3363 expect(TRUE, res);
3364 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3365 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3366 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3367 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3368 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3369 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3370 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3372 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3373 "ownerdata select all notification", FALSE);
3375 /* deselect all */
3376 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3377 item.stateMask = LVIS_SELECTED;
3378 item.state = 0;
3380 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3381 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3382 expect(TRUE, res);
3383 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3384 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3385 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3386 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3387 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3388 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3389 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3391 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3392 "ownerdata deselect all notification", TRUE);
3394 /* nothing selected, deselect all again */
3395 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3396 item.stateMask = LVIS_SELECTED;
3397 item.state = 0;
3399 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3400 expect(TRUE, res);
3402 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3404 /* select one, then deselect all */
3405 item.stateMask = LVIS_SELECTED;
3406 item.state = LVIS_SELECTED;
3407 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3408 expect(TRUE, res);
3409 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3410 item.stateMask = LVIS_SELECTED;
3411 item.state = 0;
3413 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3414 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3415 expect(TRUE, res);
3416 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3417 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3418 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3419 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3420 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3421 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3422 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3424 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3425 "ownerdata select all notification", TRUE);
3427 /* remove focused, try to focus all */
3428 item.stateMask = LVIS_FOCUSED;
3429 item.state = LVIS_FOCUSED;
3430 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3431 expect(TRUE, res);
3432 item.stateMask = LVIS_FOCUSED;
3433 item.state = 0;
3434 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3435 expect(TRUE, res);
3436 item.stateMask = LVIS_FOCUSED;
3437 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3438 expect(0, res);
3440 /* setting all to focused returns failure value */
3441 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3442 item.stateMask = LVIS_FOCUSED;
3443 item.state = LVIS_FOCUSED;
3445 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3446 expect(FALSE, res);
3448 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3449 "ownerdata focus all notification", FALSE);
3451 /* focus single item, remove all */
3452 item.stateMask = LVIS_FOCUSED;
3453 item.state = LVIS_FOCUSED;
3454 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3455 expect(TRUE, res);
3456 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3457 item.stateMask = LVIS_FOCUSED;
3458 item.state = 0;
3460 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3461 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3462 expect(TRUE, res);
3463 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3464 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3465 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3466 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3467 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3468 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3469 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3471 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3472 "ownerdata remove focus all notification", TRUE);
3474 /* set all cut */
3475 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3476 item.stateMask = LVIS_CUT;
3477 item.state = LVIS_CUT;
3479 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3480 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3481 expect(TRUE, res);
3482 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3483 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3484 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3485 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3486 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3487 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3488 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3490 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3491 "ownerdata cut all notification", FALSE);
3493 /* all marked cut, try again */
3494 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3495 item.stateMask = LVIS_CUT;
3496 item.state = LVIS_CUT;
3498 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3499 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3500 expect(TRUE, res);
3501 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3502 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3503 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3504 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3505 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3506 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3507 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3509 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3510 "ownerdata cut all notification #2", FALSE);
3512 DestroyWindow(hwnd);
3514 /* check notifications on LVM_GETITEM */
3515 /* zero callback mask */
3516 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3517 ok(hwnd != NULL, "failed to create a listview window\n");
3518 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3519 expect(1, res);
3521 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3523 memset(&item, 0, sizeof(item));
3524 item.stateMask = LVIS_SELECTED;
3525 item.mask = LVIF_STATE;
3526 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3527 expect(TRUE, res);
3529 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3530 "ownerdata getitem selected state 1", FALSE);
3532 /* non zero callback mask but not we asking for */
3533 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3534 expect(TRUE, res);
3536 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3538 memset(&item, 0, sizeof(item));
3539 item.stateMask = LVIS_SELECTED;
3540 item.mask = LVIF_STATE;
3541 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3542 expect(TRUE, res);
3544 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3545 "ownerdata getitem selected state 2", FALSE);
3547 /* LVIS_OVERLAYMASK callback mask, asking for index */
3548 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3550 memset(&item, 0, sizeof(item));
3551 item.stateMask = LVIS_OVERLAYMASK;
3552 item.mask = LVIF_STATE;
3553 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3554 expect(TRUE, res);
3556 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3557 "ownerdata getitem selected state 2", FALSE);
3559 DestroyWindow(hwnd);
3561 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3562 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3563 ok(hwnd != NULL, "failed to create a listview window\n");
3564 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3565 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3566 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3567 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3568 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3569 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3570 DestroyWindow(hwnd);
3571 /* apparently it's allowed to switch these style on after creation */
3572 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3573 ok(hwnd != NULL, "failed to create a listview window\n");
3574 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3575 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3576 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3577 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3578 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3579 DestroyWindow(hwnd);
3581 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3582 ok(hwnd != NULL, "failed to create a listview window\n");
3583 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3584 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3585 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3586 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3587 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3588 DestroyWindow(hwnd);
3590 /* The focused item is updated after the invalidation */
3591 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3592 ok(hwnd != NULL, "failed to create a listview window\n");
3593 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3594 expect(TRUE, res);
3596 memset(&item, 0, sizeof(item));
3597 item.stateMask = LVIS_FOCUSED;
3598 item.state = LVIS_FOCUSED;
3599 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3600 expect(TRUE, res);
3602 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3603 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3604 expect(TRUE, res);
3605 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3606 "ownerdata setitemcount", FALSE);
3608 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3609 expect(-1, res);
3610 DestroyWindow(hwnd);
3613 static void test_ownerdata_multiselect(void)
3615 HWND hwnd;
3616 DWORD res;
3617 LVITEMA item;
3618 unsigned int i;
3619 char buf[256];
3621 static const struct
3623 BOOL hold_shift;
3624 BOOL hold_control;
3625 UINT press_key;
3626 UINT selected_count;
3627 const char *context;
3628 const struct message *expected;
3629 BOOL todo;
3631 key_tests[] =
3633 /* First down then up */
3634 { TRUE, FALSE, VK_DOWN, 2, "select multiple via SHIFT+DOWN",
3635 ownerdata_multiselect_select_0_to_1_odstatechanged_seq, FALSE },
3636 { TRUE, FALSE, VK_UP, 1, "select one item via SHIFT+UP",
3637 ownerdata_multiselect_select_0_modkey_odstatechanged_seq, TRUE },
3638 { TRUE, TRUE, VK_DOWN, 2, "select multiple via SHIFT+CONTROL+DOWN",
3639 ownerdata_multiselect_select_0_to_1_odstatechanged_seq, FALSE },
3640 { TRUE, TRUE, VK_UP, 1, "select one item via SHIFT+CONTROL+UP",
3641 ownerdata_multiselect_select_0_modkey_odstatechanged_seq, TRUE },
3642 { FALSE, TRUE, VK_DOWN, 1, "keep selection but move cursor via CONTROL+DOWN",
3643 ownerdata_multiselect_move_0_to_1_odstatechanged_seq, FALSE },
3644 { TRUE, TRUE, VK_DOWN, 3, "select multiple after skip via SHIFT+CONTROL+DOWN",
3645 ownerdata_multiselect_select_0_to_2_odstatechanged_seq, FALSE },
3646 { FALSE, FALSE, VK_DOWN, 1, "deselect all, select item 3 via DOWN",
3647 ownerdata_multiselect_select_3_odstatechanged_seq, FALSE },
3648 /* First up then down */
3649 { TRUE, FALSE, VK_UP, 2, "select multiple via SHIFT+UP",
3650 ownerdata_multiselect_select_3_to_2_odstatechanged_seq, FALSE },
3651 { TRUE, FALSE, VK_DOWN, 1, "select one item via SHIFT+DOWN",
3652 ownerdata_multiselect_select_3_modkey_odstatechanged_seq, TRUE },
3653 { TRUE, TRUE, VK_UP, 2, "select multiple via SHIFT+CONTROL+UP",
3654 ownerdata_multiselect_select_3_to_2_odstatechanged_seq, FALSE },
3655 { TRUE, TRUE, VK_DOWN, 1, "select one item via SHIFT+CONTROL+DOWN",
3656 ownerdata_multiselect_select_3_modkey_odstatechanged_seq, TRUE },
3657 { FALSE, TRUE, VK_UP, 1, "keep selection but move cursor via CONTROL+UP",
3658 ownerdata_multiselect_move_3_to_2_odstatechanged_seq, FALSE },
3659 { TRUE, TRUE, VK_UP, 3, "select multiple after skip via SHIFT+CONTROL+UP",
3660 ownerdata_multiselect_select_3_to_1_odstatechanged_seq, FALSE },
3661 { FALSE, FALSE, VK_UP, 1, "deselect all, select item 0 via UP",
3662 ownerdata_multiselect_select_0_odstatechanged_seq, FALSE },
3665 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3666 ok(hwnd != NULL, "failed to create a listview window\n");
3667 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3668 expect(1, res);
3669 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3670 expect(0, res);
3672 /* Select and focus the first row */
3673 memset(&item, 0, sizeof(item));
3674 item.state = LVIS_SELECTED | LVIS_FOCUSED;
3675 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3676 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3677 expect(TRUE, res);
3678 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3679 expect(1, res);
3680 res = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
3681 expect(0, res);
3683 /* Select/deselect rows using UP/DOWN and SHIFT/CONTROL keys */
3684 for (i = 0; i < ARRAY_SIZE(key_tests); i++)
3686 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3688 if (key_tests[i].hold_shift)
3689 hold_key(VK_SHIFT);
3690 if (key_tests[i].hold_control)
3691 hold_key(VK_CONTROL);
3693 res = SendMessageA(hwnd, WM_KEYDOWN, key_tests[i].press_key, 0);
3694 expect(0, res);
3695 sprintf(buf, "ownerdata multiselect: %s", key_tests[i].context);
3696 ok_sequence(sequences, PARENT_ODSTATECHANGED_SEQ_INDEX, key_tests[i].expected,
3697 buf, key_tests[i].todo);
3698 res = SendMessageA(hwnd, WM_KEYUP, key_tests[i].press_key, 0);
3699 expect(0, res);
3701 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3702 expect(key_tests[i].selected_count, res);
3704 if (key_tests[i].hold_shift)
3705 release_key(VK_SHIFT);
3706 if (key_tests[i].hold_control)
3707 release_key(VK_CONTROL);
3710 DestroyWindow(hwnd);
3713 static void test_norecompute(void)
3715 static CHAR testA[] = "test";
3716 CHAR buff[10];
3717 LVITEMA item;
3718 HWND hwnd;
3719 DWORD res;
3721 /* self containing control */
3722 hwnd = create_listview_control(LVS_REPORT);
3723 ok(hwnd != NULL, "failed to create a listview window\n");
3724 memset(&item, 0, sizeof(item));
3725 item.mask = LVIF_TEXT | LVIF_STATE;
3726 item.iItem = 0;
3727 item.stateMask = LVIS_SELECTED;
3728 item.state = LVIS_SELECTED;
3729 item.pszText = testA;
3730 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3731 expect(0, res);
3732 /* retrieve with LVIF_NORECOMPUTE */
3733 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3734 item.iItem = 0;
3735 item.pszText = buff;
3736 item.cchTextMax = ARRAY_SIZE(buff);
3737 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3738 expect(TRUE, res);
3739 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3741 item.mask = LVIF_TEXT;
3742 item.iItem = 1;
3743 item.pszText = LPSTR_TEXTCALLBACKA;
3744 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3745 expect(1, res);
3747 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3748 item.iItem = 1;
3749 item.pszText = buff;
3750 item.cchTextMax = ARRAY_SIZE(buff);
3752 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3753 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3754 expect(TRUE, res);
3755 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3756 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3757 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3759 DestroyWindow(hwnd);
3761 /* LVS_OWNERDATA */
3762 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3763 ok(hwnd != NULL, "failed to create a listview window\n");
3765 item.mask = LVIF_STATE;
3766 item.stateMask = LVIS_SELECTED;
3767 item.state = LVIS_SELECTED;
3768 item.iItem = 0;
3769 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3770 expect(0, res);
3772 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3773 item.iItem = 0;
3774 item.pszText = buff;
3775 item.cchTextMax = ARRAY_SIZE(buff);
3776 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3777 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3778 expect(TRUE, res);
3779 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3780 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3781 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3783 DestroyWindow(hwnd);
3786 static void test_nosortheader(void)
3788 HWND hwnd, header;
3789 LONG_PTR style;
3791 hwnd = create_listview_control(LVS_REPORT);
3792 ok(hwnd != NULL, "failed to create a listview window\n");
3794 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3795 ok(IsWindow(header), "header expected\n");
3797 style = GetWindowLongPtrA(header, GWL_STYLE);
3798 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3800 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3801 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3802 /* HDS_BUTTONS retained */
3803 style = GetWindowLongPtrA(header, GWL_STYLE);
3804 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3806 DestroyWindow(hwnd);
3808 /* create with LVS_NOSORTHEADER */
3809 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3810 ok(hwnd != NULL, "failed to create a listview window\n");
3812 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3813 ok(IsWindow(header), "header expected\n");
3815 style = GetWindowLongPtrA(header, GWL_STYLE);
3816 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3818 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3819 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3820 /* not changed here */
3821 style = GetWindowLongPtrA(header, GWL_STYLE);
3822 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3824 DestroyWindow(hwnd);
3827 static void test_setredraw(void)
3829 HWND hwnd;
3830 DWORD_PTR style;
3831 DWORD ret;
3832 HDC hdc;
3833 RECT rect;
3835 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3836 ok(hwnd != NULL, "failed to create a listview window\n");
3838 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3839 ListView seems to handle it internally without DefWinProc */
3841 /* default value first */
3842 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3843 expect(0, ret);
3844 /* disable */
3845 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3846 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3847 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3848 expect(0, ret);
3849 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3850 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3851 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3852 expect(0, ret);
3854 /* check update rect after redrawing */
3855 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3856 expect(0, ret);
3857 InvalidateRect(hwnd, NULL, FALSE);
3858 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3859 rect.right = rect.bottom = 1;
3860 GetUpdateRect(hwnd, &rect, FALSE);
3861 expect(0, rect.right);
3862 expect(0, rect.bottom);
3864 /* WM_ERASEBKGND */
3865 hdc = GetWindowDC(hwndparent);
3866 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3867 expect(TRUE, ret);
3868 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3869 expect(0, ret);
3870 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3871 expect(TRUE, ret);
3872 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3873 expect(0, ret);
3874 ReleaseDC(hwndparent, hdc);
3876 /* check notification messages to show that repainting is disabled */
3877 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3878 expect(TRUE, ret);
3879 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3880 expect(0, ret);
3881 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3883 InvalidateRect(hwnd, NULL, TRUE);
3884 UpdateWindow(hwnd);
3885 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3886 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3888 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3889 expect(TRUE, ret);
3890 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3891 InvalidateRect(hwnd, NULL, TRUE);
3892 UpdateWindow(hwnd);
3893 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3894 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3896 /* message isn't forwarded to header */
3897 subclass_header(hwnd);
3898 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3899 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3900 expect(0, ret);
3901 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3902 "WM_SETREDRAW: not forwarded to header", FALSE);
3904 DestroyWindow(hwnd);
3907 static void test_hittest(void)
3909 HWND hwnd;
3910 DWORD r;
3911 RECT bounds;
3912 LVITEMA item;
3913 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3914 POINT pos;
3915 INT x, y, i;
3916 WORD vert;
3917 HIMAGELIST himl, himl2;
3918 HBITMAP hbmp;
3920 hwnd = create_listview_control(LVS_REPORT);
3921 ok(hwnd != NULL, "failed to create a listview window\n");
3923 /* LVS_REPORT with a single subitem (2 columns) */
3924 insert_column(hwnd, 0);
3925 insert_column(hwnd, 1);
3926 insert_item(hwnd, 0);
3928 item.iSubItem = 0;
3929 /* the only purpose of that line is to be as long as a half item rect */
3930 item.pszText = text;
3931 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3932 expect(TRUE, r);
3934 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3935 expect(TRUE, r);
3936 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3937 expect(TRUE, r);
3939 SetRect(&bounds, LVIR_BOUNDS, 0, 0, 0);
3940 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3941 expect(1, r);
3942 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3943 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3944 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3945 vert = HIWORD(r);
3946 ok(bounds.bottom - bounds.top == vert,
3947 "Vertical spacing inconsistent (%ld != %d)\n", bounds.bottom - bounds.top, vert);
3948 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3949 expect(TRUE, r);
3951 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3953 /* outside columns by x position - valid is [0, 199] */
3954 x = -1;
3955 y = pos.y + (bounds.bottom - bounds.top) / 2;
3956 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3957 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3959 x = pos.x + 50; /* column half width */
3960 y = pos.y + (bounds.bottom - bounds.top) / 2;
3961 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3962 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3963 x = pos.x + 150; /* outside column */
3964 y = pos.y + (bounds.bottom - bounds.top) / 2;
3965 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3966 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3967 y = (bounds.bottom - bounds.top) / 2;
3968 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3969 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3970 /* outside possible client rectangle (to right) */
3971 x = pos.x + 500;
3972 y = pos.y + (bounds.bottom - bounds.top) / 2;
3973 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3974 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3975 y = (bounds.bottom - bounds.top) / 2;
3976 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3977 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3978 /* subitem returned with -1 item too */
3979 x = pos.x + 150;
3980 y = bounds.top - vert;
3981 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3982 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3983 /* return values appear to underflow with negative indices */
3984 i = -2;
3985 y = y - vert;
3986 while (i > -10) {
3987 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3988 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3989 y = y - vert;
3990 i--;
3992 /* parent client area is 100x100 by default */
3993 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
3994 x = pos.x + 150; /* outside column */
3995 y = pos.y + (bounds.bottom - bounds.top) / 2;
3996 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
3997 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3998 y = (bounds.bottom - bounds.top) / 2;
3999 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
4000 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4001 /* the same with LVS_EX_FULLROWSELECT */
4002 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
4003 x = pos.x + 150; /* outside column */
4004 y = pos.y + (bounds.bottom - bounds.top) / 2;
4005 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
4006 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4007 y = (bounds.bottom - bounds.top) / 2;
4008 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4009 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
4010 x = pos.x + 150; /* outside column */
4011 y = pos.y + (bounds.bottom - bounds.top) / 2;
4012 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
4013 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4014 y = (bounds.bottom - bounds.top) / 2;
4015 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
4016 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4017 /* outside possible client rectangle (to right) */
4018 x = pos.x + 500;
4019 y = pos.y + (bounds.bottom - bounds.top) / 2;
4020 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
4021 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
4022 y = (bounds.bottom - bounds.top) / 2;
4023 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
4024 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
4025 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
4026 himl = pImageList_Create(16, 16, 0, 4, 4);
4027 ok(himl != NULL, "failed to create imagelist\n");
4028 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
4029 ok(hbmp != NULL, "failed to create bitmap\n");
4030 r = pImageList_Add(himl, hbmp, 0);
4031 ok(r == 0, "should be zero\n");
4032 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
4033 ok(hbmp != NULL, "failed to create bitmap\n");
4034 r = pImageList_Add(himl, hbmp, 0);
4035 ok(r == 1, "should be one\n");
4037 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4038 expect(0, r);
4040 item.mask = LVIF_IMAGE;
4041 item.iImage = 0;
4042 item.iItem = 0;
4043 item.iSubItem = 0;
4044 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4045 expect(TRUE, r);
4046 /* on state icon */
4047 x = pos.x + 8;
4048 y = pos.y + (bounds.bottom - bounds.top) / 2;
4049 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
4050 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4051 y = (bounds.bottom - bounds.top) / 2;
4052 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4054 /* state icons indices are 1 based, check with valid index */
4055 item.mask = LVIF_STATE;
4056 item.state = INDEXTOSTATEIMAGEMASK(1);
4057 item.stateMask = LVIS_STATEIMAGEMASK;
4058 item.iItem = 0;
4059 item.iSubItem = 0;
4060 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4061 expect(TRUE, r);
4062 /* on state icon */
4063 x = pos.x + 8;
4064 y = pos.y + (bounds.bottom - bounds.top) / 2;
4065 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
4066 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4067 y = (bounds.bottom - bounds.top) / 2;
4068 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4070 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4071 ok(himl2 == himl, "should return handle\n");
4073 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4074 expect(0, r);
4075 /* on item icon */
4076 x = pos.x + 8;
4077 y = pos.y + (bounds.bottom - bounds.top) / 2;
4078 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
4079 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
4080 y = (bounds.bottom - bounds.top) / 2;
4081 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
4083 DestroyWindow(hwnd);
4086 static void test_getviewrect(void)
4088 HWND hwnd;
4089 DWORD r;
4090 RECT rect;
4091 LVITEMA item;
4093 hwnd = create_listview_control(LVS_REPORT);
4094 ok(hwnd != NULL, "failed to create a listview window\n");
4096 /* empty */
4097 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4098 expect(TRUE, r);
4100 insert_column(hwnd, 0);
4101 insert_column(hwnd, 1);
4103 memset(&item, 0, sizeof(item));
4104 item.iItem = 0;
4105 item.iSubItem = 0;
4106 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4107 ok(!r, "got %ld\n", r);
4109 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4110 expect(TRUE, r);
4111 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
4112 expect(TRUE, r);
4114 SetRect(&rect, -1, -1, -1, -1);
4115 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4116 expect(TRUE, r);
4117 /* left is set to (2e31-1) - XP SP2 */
4118 expect(0, rect.right);
4119 expect(0, rect.top);
4120 expect(0, rect.bottom);
4122 /* switch to LVS_ICON */
4123 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
4125 SetRect(&rect, -1, -1, -1, -1);
4126 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4127 expect(TRUE, r);
4128 expect(0, rect.left);
4129 expect(0, rect.top);
4130 /* precise value differs for 2k, XP and Vista */
4131 ok(rect.bottom > 0, "Expected positive bottom value, got %ld\n", rect.bottom);
4132 ok(rect.right > 0, "Expected positive right value, got %ld\n", rect.right);
4134 DestroyWindow(hwnd);
4137 static void test_getitemposition(void)
4139 HWND hwnd, header;
4140 DWORD r;
4141 POINT pt;
4142 RECT rect;
4144 hwnd = create_listview_control(LVS_REPORT);
4145 ok(hwnd != NULL, "failed to create a listview window\n");
4146 header = subclass_header(hwnd);
4148 /* LVS_REPORT, single item, no columns added */
4149 insert_item(hwnd, 0);
4151 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4153 pt.x = pt.y = -1;
4154 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4155 expect(TRUE, r);
4156 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
4158 /* LVS_REPORT, single item, single column */
4159 insert_column(hwnd, 0);
4161 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4163 pt.x = pt.y = -1;
4164 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4165 expect(TRUE, r);
4166 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
4168 SetRectEmpty(&rect);
4169 r = SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
4170 ok(r, "got %ld\n", r);
4171 /* some padding? */
4172 expect(2, pt.x);
4173 /* offset by header height */
4174 expect(rect.bottom - rect.top, pt.y);
4176 DestroyWindow(hwnd);
4179 static void test_getitemrect(void)
4181 HWND hwnd;
4182 HIMAGELIST himl, himl_ret;
4183 HBITMAP hbm;
4184 RECT rect;
4185 DWORD r;
4186 LVITEMA item;
4187 LVCOLUMNA col;
4188 INT order[2];
4189 POINT pt;
4191 /* rectangle isn't empty for empty text items */
4192 hwnd = create_listview_control(LVS_LIST);
4193 memset(&item, 0, sizeof(item));
4194 item.mask = 0;
4195 item.iItem = 0;
4196 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4197 expect(0, r);
4198 rect.left = LVIR_LABEL;
4199 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4200 expect(TRUE, r);
4201 expect(0, rect.left);
4202 expect(0, rect.top);
4203 /* estimate it as width / height ratio */
4204 todo_wine
4205 ok((rect.right / rect.bottom) >= 5, "got right %ld, bottom %ld\n", rect.right, rect.bottom);
4206 DestroyWindow(hwnd);
4208 hwnd = create_listview_control(LVS_REPORT);
4209 ok(hwnd != NULL, "failed to create a listview window\n");
4211 /* empty item */
4212 memset(&item, 0, sizeof(item));
4213 item.iItem = 0;
4214 item.iSubItem = 0;
4215 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4216 expect(0, r);
4218 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4219 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4220 expect(TRUE, r);
4222 /* zero width rectangle with no padding */
4223 expect(0, rect.left);
4224 expect(0, rect.right);
4226 insert_column(hwnd, 0);
4227 insert_column(hwnd, 1);
4229 col.mask = LVCF_WIDTH;
4230 col.cx = 50;
4231 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
4232 expect(TRUE, r);
4234 col.mask = LVCF_WIDTH;
4235 col.cx = 100;
4236 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
4237 expect(TRUE, r);
4239 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4240 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4241 expect(TRUE, r);
4243 /* still no left padding */
4244 expect(0, rect.left);
4245 expect(150, rect.right);
4247 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4248 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4249 expect(TRUE, r);
4250 /* padding */
4251 expect(2, rect.left);
4253 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4254 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4255 expect(TRUE, r);
4256 /* padding, column width */
4257 expect(2, rect.left);
4258 expect(50, rect.right);
4260 /* no icons attached */
4261 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4262 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4263 expect(TRUE, r);
4264 /* padding */
4265 expect(2, rect.left);
4266 expect(2, rect.right);
4268 /* change order */
4269 order[0] = 1; order[1] = 0;
4270 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4271 expect(TRUE, r);
4272 pt.x = -1;
4273 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4274 expect(TRUE, r);
4275 /* 1 indexed column width + padding */
4276 expect(102, pt.x);
4277 /* rect is at zero too */
4278 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4279 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4280 expect(TRUE, r);
4281 expect(0, rect.left);
4282 /* just width sum */
4283 expect(150, rect.right);
4285 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4286 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4287 expect(TRUE, r);
4288 /* column width + padding */
4289 expect(102, rect.left);
4291 /* back to initial order */
4292 order[0] = 0; order[1] = 1;
4293 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4294 expect(TRUE, r);
4296 /* state icons */
4297 himl = pImageList_Create(16, 16, 0, 2, 2);
4298 ok(himl != NULL, "failed to create imagelist\n");
4299 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4300 ok(hbm != NULL, "failed to create bitmap\n");
4301 r = pImageList_Add(himl, hbm, 0);
4302 expect(0, r);
4303 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4304 ok(hbm != NULL, "failed to create bitmap\n");
4305 r = pImageList_Add(himl, hbm, 0);
4306 expect(1, r);
4308 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4309 expect(0, r);
4311 item.mask = LVIF_STATE;
4312 item.state = INDEXTOSTATEIMAGEMASK(1);
4313 item.stateMask = LVIS_STATEIMAGEMASK;
4314 item.iItem = 0;
4315 item.iSubItem = 0;
4316 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4317 expect(TRUE, r);
4319 /* icon bounds */
4320 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4321 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4322 expect(TRUE, r);
4323 /* padding + stateicon width */
4324 expect(18, rect.left);
4325 expect(18, rect.right);
4326 /* label bounds */
4327 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4328 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4329 expect(TRUE, r);
4330 /* padding + stateicon width -> column width */
4331 expect(18, rect.left);
4332 expect(50, rect.right);
4334 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4335 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4337 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4338 expect(0, r);
4340 item.mask = LVIF_STATE | LVIF_IMAGE;
4341 item.iImage = 1;
4342 item.state = 0;
4343 item.stateMask = ~0;
4344 item.iItem = 0;
4345 item.iSubItem = 0;
4346 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4347 expect(TRUE, r);
4349 /* icon bounds */
4350 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4351 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4352 expect(TRUE, r);
4353 /* padding, icon width */
4354 expect(2, rect.left);
4355 expect(18, rect.right);
4356 /* label bounds */
4357 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4358 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4359 expect(TRUE, r);
4360 /* padding + icon width -> column width */
4361 expect(18, rect.left);
4362 expect(50, rect.right);
4364 /* select bounds */
4365 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4366 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4367 expect(TRUE, r);
4368 /* padding, column width */
4369 expect(2, rect.left);
4370 expect(50, rect.right);
4372 /* try with indentation */
4373 item.mask = LVIF_INDENT;
4374 item.iIndent = 1;
4375 item.iItem = 0;
4376 item.iSubItem = 0;
4377 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4378 expect(TRUE, r);
4380 /* bounds */
4381 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4382 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4383 expect(TRUE, r);
4384 /* padding + 1 icon width, column width */
4385 expect(0, rect.left);
4386 expect(150, rect.right);
4388 /* select bounds */
4389 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4390 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4391 expect(TRUE, r);
4392 /* padding + 1 icon width, column width */
4393 expect(2 + 16, rect.left);
4394 expect(50, rect.right);
4396 /* label bounds */
4397 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4398 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4399 expect(TRUE, r);
4400 /* padding + 2 icon widths, column width */
4401 expect(2 + 16*2, rect.left);
4402 expect(50, rect.right);
4404 /* icon bounds */
4405 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4406 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4407 expect(TRUE, r);
4408 /* padding + 1 icon width indentation, icon width */
4409 expect(2 + 16, rect.left);
4410 expect(34, rect.right);
4412 DestroyWindow(hwnd);
4415 static void test_editbox(void)
4417 static CHAR testitemA[] = "testitem";
4418 static CHAR testitem1A[] = "testitem_quitelongname";
4419 static CHAR testitem2A[] = "testITEM_quitelongname";
4420 static CHAR buffer[25];
4421 HWND hwnd, hwndedit, hwndedit2, header;
4422 LVITEMA item;
4423 INT r;
4425 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4426 ok(hwnd != NULL, "failed to create a listview window\n");
4428 insert_column(hwnd, 0);
4430 memset(&item, 0, sizeof(item));
4431 item.mask = LVIF_TEXT;
4432 item.pszText = testitemA;
4433 item.iItem = 0;
4434 item.iSubItem = 0;
4435 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4436 expect(0, r);
4438 /* test notifications without edit created */
4439 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4440 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4441 expect(0, r);
4442 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4443 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4444 /* same thing but with valid window */
4445 hwndedit = CreateWindowA(WC_EDITA, "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4446 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4447 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4448 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4449 expect(0, r);
4450 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4451 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4452 DestroyWindow(hwndedit);
4454 /* setting focus is necessary */
4455 SetFocus(hwnd);
4456 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4457 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4459 /* test children Z-order after Edit box created */
4460 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4461 ok(IsWindow(header), "Expected header to be created\n");
4462 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4463 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4465 /* modify initial string */
4466 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4467 expect(TRUE, r);
4469 /* edit window is resized and repositioned,
4470 check again for Z-order - it should be preserved */
4471 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4472 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4474 /* return focus to listview */
4475 SetFocus(hwnd);
4477 memset(&item, 0, sizeof(item));
4478 item.mask = LVIF_TEXT;
4479 item.pszText = buffer;
4480 item.cchTextMax = sizeof(buffer);
4481 item.iItem = 0;
4482 item.iSubItem = 0;
4483 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4484 expect(TRUE, r);
4486 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4488 /* send LVM_EDITLABEL on already created edit */
4489 SetFocus(hwnd);
4490 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4491 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4492 /* focus will be set to edit */
4493 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4494 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4495 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4497 /* creating label disabled when control isn't focused */
4498 SetFocus(0);
4499 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4500 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4502 /* check EN_KILLFOCUS handling */
4503 memset(&item, 0, sizeof(item));
4504 item.pszText = testitemA;
4505 item.iItem = 0;
4506 item.iSubItem = 0;
4507 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4508 expect(TRUE, r);
4510 SetFocus(hwnd);
4511 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4512 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4513 /* modify edit and notify control that it lost focus */
4514 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4515 expect(TRUE, r);
4516 g_editbox_disp_info.item.pszText = NULL;
4517 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4518 expect(0, r);
4519 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4521 memset(&item, 0, sizeof(item));
4522 item.pszText = buffer;
4523 item.cchTextMax = sizeof(buffer);
4524 item.iItem = 0;
4525 item.iSubItem = 0;
4526 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4527 expect(lstrlenA(item.pszText), r);
4528 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4529 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4531 /* change item name to differ in casing only */
4532 SetFocus(hwnd);
4533 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4534 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4535 /* modify edit and notify control that it lost focus */
4536 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4537 expect(TRUE, r);
4538 g_editbox_disp_info.item.pszText = NULL;
4539 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4540 expect(0, r);
4541 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4543 memset(&item, 0, sizeof(item));
4544 item.pszText = buffer;
4545 item.cchTextMax = sizeof(buffer);
4546 item.iItem = 0;
4547 item.iSubItem = 0;
4548 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4549 expect(lstrlenA(item.pszText), r);
4550 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4551 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4553 /* end edit without saving */
4554 SetFocus(hwnd);
4555 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4556 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4557 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4558 expect(0, r);
4559 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4560 "edit box - end edit, no change, escape", TRUE);
4561 /* end edit with saving */
4562 SetFocus(hwnd);
4563 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4564 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4565 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4566 expect(0, r);
4567 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4568 "edit box - end edit, no change, return", TRUE);
4570 memset(&item, 0, sizeof(item));
4571 item.pszText = buffer;
4572 item.cchTextMax = sizeof(buffer);
4573 item.iItem = 0;
4574 item.iSubItem = 0;
4575 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4576 expect(lstrlenA(item.pszText), r);
4577 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4579 /* LVM_EDITLABEL with -1 destroys current edit */
4580 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4581 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4582 /* no edit present */
4583 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4584 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4585 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4586 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4587 /* edit present */
4588 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4589 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4590 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4591 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4592 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4593 /* check another negative value */
4594 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4595 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4596 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4597 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4598 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4599 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4600 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4601 /* and value greater than max item index */
4602 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4603 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4604 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4605 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4606 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4607 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4608 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4609 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4611 /* messaging tests */
4612 SetFocus(hwnd);
4613 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4614 blockEdit = FALSE;
4615 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4616 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4617 /* testing only sizing messages */
4618 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4619 "edit box create - sizing", FALSE);
4621 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4622 SetFocus(hwnd);
4623 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4624 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4625 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4626 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4627 expect(0, r);
4628 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4629 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4631 DestroyWindow(hwnd);
4634 static void test_notifyformat(void)
4636 HWND hwnd, header;
4637 DWORD r;
4639 hwnd = create_listview_control(LVS_REPORT);
4640 ok(hwnd != NULL, "failed to create a listview window\n");
4642 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4643 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4644 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4645 expect(0, r);
4646 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4647 /* set */
4648 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4649 expect(0, r);
4650 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4651 ok(r == 1, "Unexpected return value %ld.\n", r);
4652 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4653 expect(1, r);
4654 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4655 expect(0, r);
4657 DestroyWindow(hwnd);
4659 /* test failure in parent WM_NOTIFYFORMAT */
4660 notifyFormat = 0;
4661 hwnd = create_listview_control(LVS_REPORT);
4662 ok(hwnd != NULL, "failed to create a listview window\n");
4663 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4664 ok(IsWindow(header), "expected header to be created\n");
4665 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4666 expect(0, r);
4667 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4668 ok( r == 1, "Expected 1, got %ld\n", r );
4669 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4670 ok(r != 0, "Expected valid format\n");
4672 notifyFormat = NFR_UNICODE;
4673 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4674 expect(NFR_UNICODE, r);
4675 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4676 expect(1, r);
4677 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4678 ok( r == 1, "Expected 1, got %ld\n", r );
4680 notifyFormat = NFR_ANSI;
4681 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4682 expect(NFR_ANSI, r);
4683 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4684 expect(0, r);
4685 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4686 ok( r == 1, "Expected 1, got %ld\n", r );
4688 DestroyWindow(hwnd);
4690 hwndparentW = create_parent_window(TRUE);
4691 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4692 if (!IsWindow(hwndparentW)) return;
4694 notifyFormat = -1;
4695 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4696 ok(hwnd != NULL, "failed to create a listview window\n");
4697 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4698 ok(IsWindow(header), "expected header to be created\n");
4699 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4700 expect(1, r);
4701 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4702 expect(1, r);
4703 DestroyWindow(hwnd);
4704 /* receiving error code defaulting to ansi */
4705 notifyFormat = 0;
4706 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4707 ok(hwnd != NULL, "failed to create a listview window\n");
4708 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4709 ok(IsWindow(header), "expected header to be created\n");
4710 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4711 expect(0, r);
4712 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4713 expect(1, r);
4714 DestroyWindow(hwnd);
4715 /* receiving ansi code from unicode window, use it */
4716 notifyFormat = NFR_ANSI;
4717 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4718 ok(hwnd != NULL, "failed to create a listview window\n");
4719 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4720 ok(IsWindow(header), "expected header to be created\n");
4721 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4722 expect(0, r);
4723 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4724 expect(1, r);
4725 DestroyWindow(hwnd);
4726 /* unicode listview with ansi parent window */
4727 notifyFormat = -1;
4728 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4729 ok(hwnd != NULL, "failed to create a listview window\n");
4730 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4731 ok(IsWindow(header), "expected header to be created\n");
4732 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4733 expect(0, r);
4734 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4735 expect(1, r);
4736 DestroyWindow(hwnd);
4737 /* unicode listview with ansi parent window, return error code */
4738 notifyFormat = 0;
4739 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4740 ok(hwnd != NULL, "failed to create a listview window\n");
4741 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4742 ok(IsWindow(header), "expected header to be created\n");
4743 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4744 expect(0, r);
4745 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4746 expect(1, r);
4747 DestroyWindow(hwnd);
4749 DestroyWindow(hwndparentW);
4752 static void test_indentation(void)
4754 HWND hwnd;
4755 LVITEMA item;
4756 DWORD r;
4758 hwnd = create_listview_control(LVS_REPORT);
4759 ok(hwnd != NULL, "failed to create a listview window\n");
4761 memset(&item, 0, sizeof(item));
4762 item.mask = LVIF_INDENT;
4763 item.iItem = 0;
4764 item.iIndent = I_INDENTCALLBACK;
4765 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4766 expect(0, r);
4768 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4770 item.iItem = 0;
4771 item.mask = LVIF_INDENT;
4772 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4773 expect(TRUE, r);
4775 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4776 "get indent dispinfo", FALSE);
4778 /* Ask for iIndent with invalid subitem. */
4779 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4781 memset(&item, 0, sizeof(item));
4782 item.mask = LVIF_INDENT;
4783 item.iSubItem = 1;
4784 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4785 ok(r, "Failed to get item.\n");
4787 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get indent dispinfo 2", FALSE);
4789 DestroyWindow(hwnd);
4792 static void test_get_set_view(void)
4794 HWND hwnd;
4795 DWORD ret;
4796 DWORD_PTR style;
4798 /* test style->view mapping */
4799 hwnd = create_listview_control(LVS_REPORT);
4800 ok(hwnd != NULL, "failed to create a listview window\n");
4802 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4803 expect(LV_VIEW_DETAILS, ret);
4805 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4806 /* LVS_ICON == 0 */
4807 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4808 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4809 expect(LV_VIEW_ICON, ret);
4811 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4812 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4813 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4814 expect(LV_VIEW_SMALLICON, ret);
4816 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4817 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4818 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4819 expect(LV_VIEW_LIST, ret);
4821 /* switching view doesn't touch window style */
4822 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4823 expect(1, ret);
4824 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4825 ok(style & LVS_LIST, "Expected style to be preserved\n");
4826 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4827 expect(1, ret);
4828 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4829 ok(style & LVS_LIST, "Expected style to be preserved\n");
4830 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4831 expect(1, ret);
4832 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4833 ok(style & LVS_LIST, "Expected style to be preserved\n");
4835 /* now change window style to see if view is remapped */
4836 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4837 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4838 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4839 expect(LV_VIEW_SMALLICON, ret);
4841 DestroyWindow(hwnd);
4844 static void test_canceleditlabel(void)
4846 HWND hwnd, hwndedit;
4847 DWORD ret;
4848 CHAR buff[10];
4849 LVITEMA itema;
4850 static CHAR test[] = "test";
4851 static const CHAR test1[] = "test1";
4853 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4854 ok(hwnd != NULL, "failed to create a listview window\n");
4856 insert_item(hwnd, 0);
4858 /* try without edit created */
4859 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4860 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4861 expect(TRUE, ret);
4862 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4863 "cancel edit label without edit", FALSE);
4865 /* cancel without data change */
4866 SetFocus(hwnd);
4867 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4868 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4869 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4870 expect(TRUE, ret);
4871 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4873 /* cancel after data change */
4874 memset(&itema, 0, sizeof(itema));
4875 itema.pszText = test;
4876 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4877 expect(TRUE, ret);
4878 SetFocus(hwnd);
4879 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4880 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4881 ret = SetWindowTextA(hwndedit, test1);
4882 expect(1, ret);
4883 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4884 expect(TRUE, ret);
4885 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4886 memset(&itema, 0, sizeof(itema));
4887 itema.pszText = buff;
4888 itema.cchTextMax = ARRAY_SIZE(buff);
4889 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4890 expect(5, ret);
4891 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4893 DestroyWindow(hwnd);
4896 static void test_mapidindex(void)
4898 HWND hwnd;
4899 INT ret;
4901 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4902 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4903 ok(hwnd != NULL, "failed to create a listview window\n");
4904 insert_item(hwnd, 0);
4905 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4906 expect(-1, ret);
4907 DestroyWindow(hwnd);
4909 hwnd = create_listview_control(LVS_REPORT);
4910 ok(hwnd != NULL, "failed to create a listview window\n");
4912 /* LVM_MAPINDEXTOID with invalid index */
4913 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4914 expect(-1, ret);
4916 insert_item(hwnd, 0);
4917 insert_item(hwnd, 1);
4919 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4920 expect(-1, ret);
4921 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4922 expect(-1, ret);
4924 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4925 expect(0, ret);
4926 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4927 expect(1, ret);
4928 /* remove 0 indexed item, id retained */
4929 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4930 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4931 expect(1, ret);
4932 /* new id starts from previous value */
4933 insert_item(hwnd, 1);
4934 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4935 expect(2, ret);
4937 /* get index by id */
4938 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4939 expect(-1, ret);
4940 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4941 expect(-1, ret);
4942 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4943 expect(0, ret);
4944 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4945 expect(1, ret);
4947 DestroyWindow(hwnd);
4950 static void test_getitemspacing(void)
4952 HWND hwnd;
4953 DWORD ret;
4954 INT cx, cy;
4955 HIMAGELIST himl40, himl80;
4957 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4958 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4960 /* LVS_ICON */
4961 hwnd = create_listview_control(LVS_ICON);
4962 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4963 expect(cx, LOWORD(ret));
4964 expect(cy, HIWORD(ret));
4966 /* now try with icons */
4967 himl40 = pImageList_Create(40, 40, 0, 4, 4);
4968 ok(himl40 != NULL, "failed to create imagelist\n");
4969 himl80 = pImageList_Create(80, 80, 0, 4, 4);
4970 ok(himl80 != NULL, "failed to create imagelist\n");
4971 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4972 expect(0, ret);
4974 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4975 /* spacing + icon size returned */
4976 expect(cx + 40, LOWORD(ret));
4977 expect(cy + 40, HIWORD(ret));
4978 /* try changing icon size */
4979 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4981 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4982 /* spacing + icon size returned */
4983 expect(cx + 80, LOWORD(ret));
4984 expect(cy + 80, HIWORD(ret));
4986 /* set own icon spacing */
4987 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4988 expect(cx + 80, LOWORD(ret));
4989 expect(cy + 80, HIWORD(ret));
4991 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4992 /* set size returned */
4993 expect(100, LOWORD(ret));
4994 expect(100, HIWORD(ret));
4996 /* now change image list - icon spacing should be unaffected */
4997 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4999 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5000 /* set size returned */
5001 expect(100, LOWORD(ret));
5002 expect(100, HIWORD(ret));
5004 /* spacing = 0 - keep previous value */
5005 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
5006 expect(100, LOWORD(ret));
5007 expect(100, HIWORD(ret));
5009 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5010 expect(100, LOWORD(ret));
5012 expect(0xFFFF, HIWORD(ret));
5014 if (sizeof(void*) == 8)
5016 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
5017 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
5018 expect(100, LOWORD(ret));
5019 expect(0xFFFF, HIWORD(ret));
5021 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
5022 expect(0xFFFF, LOWORD(ret));
5023 expect(0xFFFF, HIWORD(ret));
5025 else
5027 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
5028 expect(100, LOWORD(ret));
5029 expect(0xFFFF, HIWORD(ret));
5031 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5032 /* spacing + icon size returned */
5033 expect(cx + 40, LOWORD(ret));
5034 expect(cy + 40, HIWORD(ret));
5036 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
5037 pImageList_Destroy(himl80);
5038 DestroyWindow(hwnd);
5039 /* LVS_SMALLICON */
5040 hwnd = create_listview_control(LVS_SMALLICON);
5041 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5042 expect(cx, LOWORD(ret));
5043 expect(cy, HIWORD(ret));
5045 /* spacing does not depend on selected view type */
5046 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
5047 expect(0, ret);
5049 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5050 /* spacing + icon size returned */
5051 expect(cx + 40, LOWORD(ret));
5052 expect(cy + 40, HIWORD(ret));
5054 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
5055 pImageList_Destroy(himl40);
5056 DestroyWindow(hwnd);
5057 /* LVS_REPORT */
5058 hwnd = create_listview_control(LVS_REPORT);
5059 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5060 expect(cx, LOWORD(ret));
5061 expect(cy, HIWORD(ret));
5063 DestroyWindow(hwnd);
5064 /* LVS_LIST */
5065 hwnd = create_listview_control(LVS_LIST);
5066 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5067 expect(cx, LOWORD(ret));
5068 expect(cy, HIWORD(ret));
5070 DestroyWindow(hwnd);
5073 static INT get_current_font_height(HWND listview)
5075 TEXTMETRICA tm;
5076 HFONT hfont;
5077 HWND hwnd;
5078 HDC hdc;
5080 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
5081 if (!hwnd)
5082 hwnd = listview;
5084 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
5085 if (!hfont) {
5086 hdc = GetDC(hwnd);
5087 GetTextMetricsA(hdc, &tm);
5088 ReleaseDC(hwnd, hdc);
5090 else {
5091 HFONT oldfont;
5093 hdc = GetDC(0);
5094 oldfont = SelectObject(hdc, hfont);
5095 GetTextMetricsA(hdc, &tm);
5096 SelectObject(hdc, oldfont);
5097 ReleaseDC(0, hdc);
5100 return tm.tmHeight;
5103 static void test_getcolumnwidth(void)
5105 HWND hwnd;
5106 INT ret;
5107 DWORD_PTR style;
5108 LVCOLUMNA col;
5109 LVITEMA itema;
5110 INT height;
5112 /* default column width */
5113 hwnd = create_listview_control(LVS_ICON);
5114 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5115 expect(0, ret);
5116 style = GetWindowLongA(hwnd, GWL_STYLE);
5117 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
5118 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5119 todo_wine expect(8, ret);
5120 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
5121 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
5122 col.mask = 0;
5123 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5124 expect(0, ret);
5125 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5126 expect(10, ret);
5127 DestroyWindow(hwnd);
5129 /* default column width with item added */
5130 hwnd = create_listview_control(LVS_LIST);
5131 memset(&itema, 0, sizeof(itema));
5132 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5133 ok(!ret, "got %d\n", ret);
5134 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5135 height = get_current_font_height(hwnd);
5136 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
5137 DestroyWindow(hwnd);
5140 static void test_scrollnotify(void)
5142 HWND hwnd;
5143 DWORD ret;
5145 hwnd = create_listview_control(LVS_REPORT);
5147 insert_column(hwnd, 0);
5148 insert_column(hwnd, 1);
5149 insert_item(hwnd, 0);
5151 /* make it scrollable - resize */
5152 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
5153 expect(TRUE, ret);
5154 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
5155 expect(TRUE, ret);
5157 /* try with dummy call */
5158 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5159 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
5160 expect(TRUE, ret);
5161 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
5162 "scroll notify 1", TRUE);
5164 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5165 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
5166 expect(TRUE, ret);
5167 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
5168 "scroll notify 2", TRUE);
5170 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5171 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
5172 expect(TRUE, ret);
5173 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
5174 "scroll notify 3", TRUE);
5176 DestroyWindow(hwnd);
5179 static void test_LVS_EX_TRANSPARENTBKGND(void)
5181 HWND hwnd;
5182 DWORD ret;
5183 HDC hdc;
5185 hwnd = create_listview_control(LVS_REPORT);
5187 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5188 expect(TRUE, ret);
5190 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5191 LVS_EX_TRANSPARENTBKGND);
5193 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
5194 if (ret != CLR_NONE)
5196 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
5197 DestroyWindow(hwnd);
5198 return;
5201 /* try to set some back color and check this style bit */
5202 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5203 expect(TRUE, ret);
5204 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
5205 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
5207 /* now test what this style actually does */
5208 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5209 LVS_EX_TRANSPARENTBKGND);
5211 hdc = GetWindowDC(hwndparent);
5213 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5214 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
5215 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
5216 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
5218 ReleaseDC(hwndparent, hdc);
5220 DestroyWindow(hwnd);
5223 static void test_approximate_viewrect(void)
5225 static CHAR test[] = "abracadabra, a very long item label";
5226 DWORD item_width, item_height, header_height;
5227 static CHAR column_header[] = "Header";
5228 unsigned const column_width = 100;
5229 DWORD ret, item_count;
5230 HIMAGELIST himl;
5231 LVITEMA itema;
5232 LVCOLUMNA col;
5233 HBITMAP hbmp;
5234 HWND hwnd;
5236 /* LVS_ICON */
5237 hwnd = create_listview_control(LVS_ICON);
5238 himl = pImageList_Create(40, 40, 0, 4, 4);
5239 ok(himl != NULL, "failed to create imagelist\n");
5240 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
5241 ok(hbmp != NULL, "failed to create bitmap\n");
5242 ret = pImageList_Add(himl, hbmp, 0);
5243 expect(0, ret);
5244 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
5245 expect(0, ret);
5247 itema.mask = LVIF_IMAGE;
5248 itema.iImage = 0;
5249 itema.iItem = 0;
5250 itema.iSubItem = 0;
5251 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5252 expect(0, ret);
5254 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
5255 ok(ret != 0, "Unexpected return value %#lx.\n", ret);
5257 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5258 expect(MAKELONG(77,827), ret);
5260 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5261 ok(ret != 0, "got 0\n");
5263 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5264 expect(MAKELONG(102,302), ret);
5266 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5267 expect(MAKELONG(52,52), ret);
5269 itema.pszText = test;
5270 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5271 expect(TRUE, ret);
5272 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5273 expect(MAKELONG(52,52), ret);
5275 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5276 expect(MAKELONG(52,2), ret);
5277 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5278 expect(MAKELONG(52,52), ret);
5279 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5280 expect(MAKELONG(102,52), ret);
5281 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5282 expect(MAKELONG(102,102), ret);
5283 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5284 expect(MAKELONG(102,102), ret);
5285 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5286 expect(MAKELONG(102,152), ret);
5287 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5288 expect(MAKELONG(102,152), ret);
5289 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5290 expect(MAKELONG(152,152), ret);
5292 DestroyWindow(hwnd);
5294 /* LVS_REPORT */
5295 hwnd = create_listview_control(LVS_REPORT);
5297 /* Empty control without columns */
5298 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100, 100));
5299 todo_wine
5300 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5301 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5303 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5304 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5305 todo_wine
5306 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5308 header_height = HIWORD(ret);
5310 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5311 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5312 todo_wine
5313 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5315 item_height = HIWORD(ret) - header_height;
5317 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5318 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5319 ok(HIWORD(ret) == (header_height - 2 * item_height), "Unexpected height %d.\n", HIWORD(ret)) ;
5321 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5322 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5323 ok(HIWORD(ret) == header_height, "Unexpected height.\n");
5324 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5325 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5326 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5328 /* Insert column */
5329 col.mask = LVCF_TEXT | LVCF_WIDTH;
5330 col.pszText = column_header;
5331 col.cx = column_width;
5332 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5333 ok(ret == 0, "Unexpected return value %ld.\n", ret);
5335 /* Empty control with column */
5336 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5337 todo_wine {
5338 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5339 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5341 header_height = HIWORD(ret);
5342 item_width = LOWORD(ret);
5344 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5345 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5346 todo_wine
5347 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5349 item_height = HIWORD(ret) - header_height;
5351 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5352 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5353 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5355 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5356 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5357 ok(HIWORD(ret) == header_height, "Unexpected height %d.\n", HIWORD(ret));
5359 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5360 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5361 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5363 for (item_count = 1; item_count <= 2; ++item_count)
5365 itema.mask = LVIF_TEXT;
5366 itema.iItem = 0;
5367 itema.iSubItem = 0;
5368 itema.pszText = test;
5369 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5370 ok(ret == 0, "Unexpected return value %ld.\n", ret);
5372 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5373 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5374 todo_wine
5375 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5377 header_height = HIWORD(ret);
5378 item_width = LOWORD(ret);
5380 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5381 ok(LOWORD(ret) == item_width, "Unexpected width %d, item %ld\n", LOWORD(ret), item_count - 1);
5382 ok(HIWORD(ret) > header_height, "Unexpected height %d. item %ld.\n", HIWORD(ret), item_count - 1);
5384 item_height = HIWORD(ret) - header_height;
5386 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5387 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5388 todo_wine
5389 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5391 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5392 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5393 ok(HIWORD(ret) == header_height + item_count * item_height, "Unexpected height %d.\n", HIWORD(ret));
5395 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5396 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5397 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5399 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELONG(item_width * 2, header_height + 3 * item_height));
5400 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5401 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5403 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(item_width * 2, 0));
5404 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5405 todo_wine
5406 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5408 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(-1, -1));
5409 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5410 todo_wine
5411 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5414 DestroyWindow(hwnd);
5418 static void test_finditem(void)
5420 LVFINDINFOA fi;
5421 static char f[5];
5422 HWND hwnd;
5423 INT r;
5425 hwnd = create_listview_control(LVS_REPORT);
5426 insert_item(hwnd, 0);
5428 memset(&fi, 0, sizeof(fi));
5430 /* full string search, inserted text was "foo" */
5431 strcpy(f, "foo");
5432 fi.flags = LVFI_STRING;
5433 fi.psz = f;
5434 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5435 expect(0, r);
5437 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5438 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5439 expect(0, r);
5441 fi.flags = LVFI_PARTIAL;
5442 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5443 expect(0, r);
5445 /* partial string search, inserted text was "foo" */
5446 strcpy(f, "fo");
5447 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5448 fi.psz = f;
5449 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5450 expect(0, r);
5452 fi.flags = LVFI_STRING;
5453 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5454 expect(-1, r);
5456 fi.flags = LVFI_PARTIAL;
5457 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5458 expect(0, r);
5460 /* partial string search, part after start char */
5461 strcpy(f, "oo");
5462 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5463 fi.psz = f;
5464 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5465 expect(-1, r);
5467 /* try with LVFI_SUBSTRING */
5468 strcpy(f, "fo");
5469 fi.flags = LVFI_SUBSTRING;
5470 fi.psz = f;
5471 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5472 expect(0, r);
5473 strcpy(f, "f");
5474 fi.flags = LVFI_SUBSTRING;
5475 fi.psz = f;
5476 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5477 expect(0, r);
5478 strcpy(f, "o");
5479 fi.flags = LVFI_SUBSTRING;
5480 fi.psz = f;
5481 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5482 expect(-1, r);
5484 strcpy(f, "o");
5485 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5486 fi.psz = f;
5487 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5488 expect(-1, r);
5490 strcpy(f, "f");
5491 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5492 fi.psz = f;
5493 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5494 expect(0, r);
5496 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5497 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5498 expect(0, r);
5500 /* Case sensitivity. */
5501 strcpy(f, "Foo");
5502 fi.flags = LVFI_STRING;
5503 fi.psz = f;
5504 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5505 ok(!r, "Unexpected item index %d.\n", r);
5507 strcpy(f, "F");
5508 fi.flags = LVFI_SUBSTRING;
5509 fi.psz = f;
5510 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5511 ok(!r, "Unexpected item index %d.\n", r);
5513 DestroyWindow(hwnd);
5516 static void test_LVS_EX_HEADERINALLVIEWS(void)
5518 HWND hwnd, header;
5519 DWORD style;
5521 hwnd = create_listview_control(LVS_ICON);
5523 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5524 LVS_EX_HEADERINALLVIEWS);
5526 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5527 if (!IsWindow(header))
5529 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5530 DestroyWindow(hwnd);
5531 return;
5534 /* LVS_NOCOLUMNHEADER works as before */
5535 style = GetWindowLongA(hwnd, GWL_STYLE);
5536 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5537 style = GetWindowLongA(header, GWL_STYLE);
5538 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5539 style = GetWindowLongA(hwnd, GWL_STYLE);
5540 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5541 style = GetWindowLongA(header, GWL_STYLE);
5542 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5544 /* try to remove style */
5545 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5546 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5547 ok(IsWindow(header), "Expected header to be created\n");
5548 style = GetWindowLongA(header, GWL_STYLE);
5549 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5551 DestroyWindow(hwnd);
5553 /* check other styles */
5554 hwnd = create_listview_control(LVS_LIST);
5555 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5556 LVS_EX_HEADERINALLVIEWS);
5557 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5558 ok(IsWindow(header), "Expected header to be created\n");
5559 DestroyWindow(hwnd);
5561 hwnd = create_listview_control(LVS_SMALLICON);
5562 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5563 LVS_EX_HEADERINALLVIEWS);
5564 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5565 ok(IsWindow(header), "Expected header to be created\n");
5566 DestroyWindow(hwnd);
5568 hwnd = create_listview_control(LVS_REPORT);
5569 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5570 LVS_EX_HEADERINALLVIEWS);
5571 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5572 ok(IsWindow(header), "Expected header to be created\n");
5573 DestroyWindow(hwnd);
5576 static void test_hover(void)
5578 HWND hwnd, fg;
5579 DWORD r;
5581 hwnd = create_listview_control(LVS_ICON);
5582 SetForegroundWindow(hwndparent);
5583 fg = GetForegroundWindow();
5584 if (fg != hwndparent)
5586 skip("Window is not in the foreground. Skipping hover tests.\n");
5587 DestroyWindow(hwnd);
5588 return;
5591 /* test WM_MOUSEHOVER forwarding */
5592 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5593 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5594 expect(0, r);
5595 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5596 g_block_hover = TRUE;
5597 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5598 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5599 expect(0, r);
5600 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5601 g_block_hover = FALSE;
5603 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5604 expect(HOVER_DEFAULT, r);
5605 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5606 expect(500, r);
5608 DestroyWindow(hwnd);
5611 static void test_destroynotify(void)
5613 HWND hwnd;
5614 BOOL ret;
5616 hwnd = create_listview_control(LVS_REPORT);
5617 ok(hwnd != NULL, "failed to create listview window\n");
5619 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5620 DestroyWindow(hwnd);
5621 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5623 /* same for ownerdata list */
5624 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5625 ok(hwnd != NULL, "failed to create listview window\n");
5627 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5628 DestroyWindow(hwnd);
5629 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5631 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5632 ok(hwnd != NULL, "failed to create listview window\n");
5634 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5635 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5636 ok(ret == TRUE, "got %d\n", ret);
5637 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5638 DestroyWindow(hwnd);
5641 static void test_header_notification(void)
5643 static char textA[] = "newtext";
5644 HWND list, header;
5645 HDITEMA item;
5646 NMHEADERA nmh;
5647 LVCOLUMNA col;
5648 DWORD ret;
5649 BOOL r;
5651 list = create_listview_control(LVS_REPORT);
5652 ok(list != NULL, "failed to create listview window\n");
5654 memset(&col, 0, sizeof(col));
5655 col.mask = LVCF_WIDTH;
5656 col.cx = 100;
5657 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5658 expect(0, ret);
5660 /* check list parent notification after header item changed,
5661 this test should be placed before header subclassing to avoid
5662 Listview -> Header messages to be logged */
5663 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5665 col.mask = LVCF_TEXT;
5666 col.pszText = textA;
5667 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5668 expect(TRUE, r);
5670 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5671 "header notify, listview", FALSE);
5672 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5673 "header notify, parent", FALSE);
5675 header = subclass_header(list);
5677 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5678 expect(1, ret);
5680 memset(&item, 0, sizeof(item));
5681 item.mask = HDI_WIDTH;
5682 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5683 expect(1, ret);
5684 expect(100, item.cxy);
5686 nmh.hdr.hwndFrom = header;
5687 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5688 nmh.hdr.code = HDN_ITEMCHANGEDA;
5689 nmh.iItem = 0;
5690 nmh.iButton = 0;
5691 item.mask = HDI_WIDTH;
5692 item.cxy = 50;
5693 nmh.pitem = &item;
5694 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5695 expect(0, ret);
5697 DestroyWindow(list);
5700 static void test_header_notification2(void)
5702 static char textA[] = "newtext";
5703 HWND list, header;
5704 HDITEMW itemW;
5705 NMHEADERW nmhdr;
5706 LVCOLUMNA col;
5707 DWORD ret;
5708 WCHAR buffer[100];
5709 struct message parent_header_notify_seq[] = {
5710 { WM_NOTIFY, sent|id, 0, 0, 0 },
5711 { 0 }
5714 list = create_listview_control(LVS_REPORT);
5715 ok(list != NULL, "failed to create listview window\n");
5717 memset(&col, 0, sizeof(col));
5718 col.mask = LVCF_WIDTH | LVCF_TEXT;
5719 col.cx = 100;
5720 col.pszText = textA;
5721 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5722 expect(0, ret);
5724 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5725 ok(header != 0, "No header\n");
5726 memset(&itemW, 0, sizeof(itemW));
5727 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5728 itemW.pszText = buffer;
5729 itemW.cchTextMax = ARRAY_SIZE(buffer);
5730 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5731 expect(1, ret);
5733 nmhdr.hdr.hwndFrom = header;
5734 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5735 nmhdr.iItem = 0;
5736 nmhdr.iButton = 0;
5737 nmhdr.pitem = &itemW;
5739 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5740 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5741 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5742 ok(ret == 0, "got %ld\n", ret);
5743 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5744 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5745 "header notify, parent", TRUE);
5746 todo_wine
5747 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5748 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5749 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5750 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5751 ok(ret == 0, "got %ld\n", ret);
5752 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5753 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5754 "header notify, parent", TRUE);
5755 todo_wine
5756 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5757 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5758 SetFocus(list);
5759 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5760 nmhdr.hdr.code = HDN_ITEMCLICKW;
5761 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5762 ok(ret == 0, "got %ld\n", ret);
5763 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5764 "header notify, parent", FALSE);
5765 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5766 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5767 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5768 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5769 ok(ret == 0, "got %ld\n", ret);
5770 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5771 "header notify, parent", FALSE);
5772 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5773 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5774 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5775 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5776 ok(ret == 0, "got %ld\n", ret);
5777 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5778 "header notify, parent", TRUE);
5779 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5780 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5781 nmhdr.hdr.code = HDN_BEGINTRACKW;
5782 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5783 ok(ret == 0, "got %ld\n", ret);
5784 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5785 "header notify, parent", FALSE);
5786 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5787 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5788 nmhdr.hdr.code = HDN_ENDTRACKW;
5789 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5790 ok(ret == 0, "got %ld\n", ret);
5791 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5792 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5793 "header notify, parent", FALSE);
5794 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5795 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5796 nmhdr.hdr.code = HDN_TRACKW;
5797 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5798 ok(ret == 0, "got %ld\n", ret);
5799 parent_header_notify_seq[0].id = HDN_TRACKA;
5800 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5801 "header notify, parent", FALSE);
5802 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5803 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5804 nmhdr.hdr.code = HDN_BEGINDRAG;
5805 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5806 ok(ret == 1, "got %ld\n", ret);
5807 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5808 "header notify, parent", FALSE);
5809 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5810 nmhdr.hdr.code = HDN_ENDDRAG;
5811 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5812 ok(ret == 0, "got %ld\n", ret);
5813 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5814 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5815 "header notify, parent", FALSE);
5816 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5817 nmhdr.hdr.code = HDN_FILTERCHANGE;
5818 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5819 ok(ret == 0, "got %ld\n", ret);
5820 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5821 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5822 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5823 "header notify, parent", FALSE);
5824 parent_header_notify_seq[0].flags &= ~optional;
5825 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5826 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
5827 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5828 ok(ret == 0, "got %ld\n", ret);
5829 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5830 "header notify, parent", FALSE);
5831 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5832 nmhdr.hdr.code = HDN_ENDFILTEREDIT;
5833 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5834 ok(ret == 0, "got %ld\n", ret);
5835 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5836 "header notify, parent", FALSE);
5837 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5838 nmhdr.hdr.code = HDN_ITEMSTATEICONCLICK;
5839 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5840 ok(ret == 0, "got %ld\n", ret);
5841 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5842 "header notify, parent", FALSE);
5843 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5844 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5845 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5846 ok(ret == 0, "got %ld\n", ret);
5847 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5848 "header notify, parent", FALSE);
5850 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5852 DestroyWindow(list);
5855 static void test_createdragimage(void)
5857 HIMAGELIST himl;
5858 POINT pt;
5859 HWND list;
5861 list = create_listview_control(LVS_ICON);
5862 ok(list != NULL, "failed to create listview window\n");
5864 insert_item(list, 0);
5866 /* NULL point */
5867 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5868 ok(himl == NULL, "got %p\n", himl);
5870 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5871 ok(himl != NULL, "got %p\n", himl);
5872 pImageList_Destroy(himl);
5874 DestroyWindow(list);
5877 static void test_dispinfo(void)
5879 static const char testA[] = "TEST";
5880 WCHAR buff[10];
5881 LVITEMA item;
5882 HWND hwnd;
5883 DWORD ret;
5885 hwnd = create_listview_control(LVS_ICON);
5886 ok(hwnd != NULL, "failed to create listview window\n");
5888 insert_item(hwnd, 0);
5890 memset(&item, 0, sizeof(item));
5891 item.pszText = LPSTR_TEXTCALLBACKA;
5892 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5893 expect(1, ret);
5895 g_disp_A_to_W = TRUE;
5896 item.pszText = (char*)buff;
5897 item.cchTextMax = ARRAY_SIZE(buff);
5898 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5899 ok(ret == sizeof(testA)-1, "got %ld, expected 4\n", ret);
5900 g_disp_A_to_W = FALSE;
5902 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5903 "got %s, expected %s\n", item.pszText, testA);
5905 DestroyWindow(hwnd);
5908 static void test_LVM_SETITEMTEXT(void)
5910 static char testA[] = "TEST";
5911 LVITEMA item;
5912 HWND hwnd;
5913 DWORD ret;
5915 hwnd = create_listview_control(LVS_ICON);
5916 ok(hwnd != NULL, "failed to create listview window\n");
5918 insert_item(hwnd, 0);
5920 /* null item pointer */
5921 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5922 expect(FALSE, ret);
5924 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5925 expect(FALSE, ret);
5927 /* index out of bounds */
5928 item.pszText = testA;
5929 item.cchTextMax = 0; /* ignored */
5930 item.iSubItem = 0;
5932 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5933 expect(FALSE, ret);
5935 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5936 expect(FALSE, ret);
5938 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5939 expect(TRUE, ret);
5941 DestroyWindow(hwnd);
5944 static void test_LVM_REDRAWITEMS(void)
5946 HWND list;
5947 DWORD ret;
5949 list = create_listview_control(LVS_ICON);
5950 ok(list != NULL, "failed to create listview window\n");
5952 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5953 expect(TRUE, ret);
5955 insert_item(list, 0);
5957 ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
5958 expect(TRUE, ret);
5960 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
5961 expect(TRUE, ret);
5963 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5964 expect(TRUE, ret);
5966 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
5967 expect(TRUE, ret);
5969 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
5970 expect(TRUE, ret);
5972 ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
5973 expect(TRUE, ret);
5975 ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
5976 expect(TRUE, ret);
5978 DestroyWindow(list);
5981 static void test_imagelists(void)
5983 HWND hwnd, header;
5984 HIMAGELIST himl1, himl2, himl3;
5985 LRESULT ret;
5987 himl1 = pImageList_Create(40, 40, 0, 4, 4);
5988 himl2 = pImageList_Create(40, 40, 0, 4, 4);
5989 himl3 = pImageList_Create(40, 40, 0, 4, 4);
5990 ok(himl1 != NULL, "Failed to create imagelist\n");
5991 ok(himl2 != NULL, "Failed to create imagelist\n");
5992 ok(himl3 != NULL, "Failed to create imagelist\n");
5994 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
5995 header = subclass_header(hwnd);
5997 ok(header != NULL, "Expected header\n");
5998 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
5999 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6001 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6003 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
6004 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6005 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6006 "set normal image list", FALSE);
6008 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6010 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
6011 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6012 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6013 "set state image list", TRUE);
6015 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6016 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6018 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6020 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
6021 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6022 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
6023 "set small image list", FALSE);
6025 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6026 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
6027 DestroyWindow(hwnd);
6029 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
6031 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6033 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
6034 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6035 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6036 "set normal image list", FALSE);
6038 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6040 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
6041 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6042 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6043 "set state image list", FALSE);
6045 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6047 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
6048 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6049 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6050 "set small image list", FALSE);
6052 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6053 ok(header == NULL, "Expected no header, got %p\n", header);
6055 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
6057 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6058 ok(header != NULL, "Expected header, got NULL\n");
6060 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6061 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
6063 DestroyWindow(hwnd);
6066 static void test_deleteitem(void)
6068 LVITEMA item;
6069 UINT state;
6070 HWND hwnd;
6071 BOOL ret;
6073 hwnd = create_listview_control(LVS_REPORT);
6075 insert_item(hwnd, 0);
6076 insert_item(hwnd, 0);
6077 insert_item(hwnd, 0);
6078 insert_item(hwnd, 0);
6079 insert_item(hwnd, 0);
6081 g_focus_test_LVN_DELETEITEM = TRUE;
6083 /* delete focused item (not the last index) */
6084 item.stateMask = LVIS_FOCUSED;
6085 item.state = LVIS_FOCUSED;
6086 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
6087 ok(ret == TRUE, "got %d\n", ret);
6088 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
6089 ok(ret == TRUE, "got %d\n", ret);
6090 /* next item gets focus */
6091 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
6092 ok(state == LVIS_FOCUSED, "got %x\n", state);
6094 /* focus last item and delete it */
6095 item.stateMask = LVIS_FOCUSED;
6096 item.state = LVIS_FOCUSED;
6097 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
6098 ok(ret == TRUE, "got %d\n", ret);
6099 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
6100 ok(ret == TRUE, "got %d\n", ret);
6101 /* new last item gets focus */
6102 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
6103 ok(state == LVIS_FOCUSED, "got %x\n", state);
6105 /* focus first item and delete it */
6106 item.stateMask = LVIS_FOCUSED;
6107 item.state = LVIS_FOCUSED;
6108 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6109 ok(ret == TRUE, "got %d\n", ret);
6110 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
6111 ok(ret == TRUE, "got %d\n", ret);
6112 /* new first item gets focus */
6113 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
6114 ok(state == LVIS_FOCUSED, "got %x\n", state);
6116 g_focus_test_LVN_DELETEITEM = FALSE;
6118 DestroyWindow(hwnd);
6121 static const struct message parent_insert_focused0_seq[] = {
6122 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGING },
6123 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGED },
6124 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6125 { 0 }
6128 static const struct message parent_insert_focused1_seq[] = {
6129 { WM_NOTIFY, sent|id|wparam|lparam, 1, LVIF_STATE, LVN_ITEMCHANGING },
6130 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGING },
6131 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGED },
6132 { WM_NOTIFY, sent|id|wparam|lparam, 1, LVIF_STATE, LVN_ITEMCHANGED },
6133 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6134 { 0 }
6137 static const struct message parent_insert_item_seq[] = {
6138 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6139 { 0 }
6142 static const struct message parent_insert_selected_seq[] = {
6143 { WM_NOTIFY, sent|id|wparam|lparam, 3, LVIF_STATE, LVN_ITEMCHANGING },
6144 { WM_NOTIFY, sent|id|wparam|lparam, 3, LVIF_STATE, LVN_ITEMCHANGED },
6145 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6146 { 0 }
6149 #define LVIS_ALL (LVIS_FOCUSED | LVIS_SELECTED | LVIS_CUT | LVIS_DROPHILITED | LVIS_ACTIVATING)
6151 static void test_LVM_INSERTITEM(void)
6153 static const struct
6155 UINT mask, state, stateMask;
6156 } insert_item[] =
6158 { LVIF_STATE, LVIS_FOCUSED, LVIS_FOCUSED },
6159 { LVIF_STATE, LVIS_FOCUSED, 0 },
6160 { LVIF_STATE, 0, LVIS_FOCUSED },
6162 { LVIF_STATE, LVIS_SELECTED, LVIS_SELECTED },
6163 { LVIF_STATE, LVIS_SELECTED, 0 },
6164 { LVIF_STATE, 0, LVIS_SELECTED },
6166 { LVIF_STATE, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED },
6167 { LVIF_STATE, LVIS_FOCUSED | LVIS_SELECTED, 0 },
6168 { LVIF_STATE, 0, LVIS_FOCUSED | LVIS_SELECTED },
6170 { LVIF_STATE, LVIS_FOCUSED, LVIS_ALL },
6171 { LVIF_STATE, LVIS_SELECTED, LVIS_ALL },
6172 { LVIF_STATE, LVIS_CUT, LVIS_ALL },
6173 { LVIF_STATE, LVIS_DROPHILITED, LVIS_ALL },
6174 { LVIF_STATE, LVIS_ACTIVATING, LVIS_ALL },
6176 { LVIF_STATE, LVIS_ALL, LVIS_ALL },
6177 { LVIF_STATE, LVIS_ALL, 0 },
6178 { LVIF_STATE, 0, LVIS_ALL },
6180 { LVIF_STATE | LVIF_PARAM, 0, 0 },
6181 { LVIF_STATE | LVIF_PARAM, LVIS_FOCUSED, LVIS_FOCUSED },
6182 { LVIF_STATE | LVIF_PARAM, LVIS_FOCUSED, 0 },
6183 { LVIF_STATE | LVIF_PARAM, 0, LVIS_FOCUSED },
6185 { LVIF_STATE | LVIF_PARAM, LVIS_SELECTED, LVIS_SELECTED },
6186 { LVIF_STATE | LVIF_PARAM, LVIS_SELECTED, 0 },
6187 { LVIF_STATE | LVIF_PARAM, 0, LVIS_SELECTED },
6189 { LVIF_STATE, 0, 0 },
6190 { LVIF_PARAM, 0, 0 },
6192 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
6193 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, LVIS_FOCUSED },
6194 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, 0 },
6195 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_FOCUSED },
6197 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
6198 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, LVIS_FOCUSED },
6199 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, 0 },
6200 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_FOCUSED },
6202 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
6203 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_ALL, LVIS_ALL },
6204 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_ALL, 0 },
6205 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_ALL },
6207 LVITEMA item;
6208 UINT state;
6209 HWND hwnd;
6210 INT ret, i;
6211 char buf[256];
6213 for (i = 0; i < ARRAYSIZE(insert_item); i++)
6215 hwnd = create_listview_control(LVS_REPORT);
6217 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6219 item.mask = insert_item[i].mask;
6220 item.state = insert_item[i].state;
6221 item.stateMask = insert_item[i].stateMask;
6222 item.pszText = (LPSTR)"Hello World!";
6223 item.iImage = I_IMAGECALLBACK;
6224 item.iItem = 0;
6225 item.iSubItem = 0;
6226 item.lParam = 0xdeadbeef;
6227 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6228 ok(ret == 0, "%d: got %d\n", i, ret);
6230 if ((insert_item[i].mask & LVIF_STATE) && (insert_item[i].state & (LVIS_FOCUSED | LVIS_SELECTED)))
6232 sprintf(buf, "%d: insert focused", i);
6233 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused0_seq, buf, FALSE);
6235 else
6237 sprintf(buf, "%d: insert item", i);
6238 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, buf, FALSE);
6241 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_ALL);
6242 if ((insert_item[i].mask & LVIF_STATE) && insert_item[i].state)
6243 ok(state == insert_item[i].state, "%d: expected %#x, got %#x\n", i, insert_item[i].state, state);
6244 else
6245 ok(state == 0, "%d: expected 0, got %#x\n", i, state);
6247 DestroyWindow(hwnd);
6251 static void test_insertitem(void)
6253 LVITEMA item;
6254 UINT state;
6255 HWND hwnd;
6256 INT ret;
6258 hwnd = create_listview_control(LVS_REPORT);
6260 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6262 /* insert item 0 focused */
6263 item.mask = LVIF_STATE;
6264 item.state = LVIS_FOCUSED;
6265 item.stateMask = LVIS_FOCUSED;
6266 item.iItem = 0;
6267 item.iSubItem = 0;
6268 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6269 ok(ret == 0, "got %d\n", ret);
6270 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused0_seq, "insert focused 0", FALSE);
6272 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
6273 ok(state == LVIS_FOCUSED, "got %x\n", state);
6275 /* insert item 1, focus shift */
6276 item.mask = LVIF_STATE;
6277 item.state = LVIS_FOCUSED;
6278 item.stateMask = LVIS_FOCUSED;
6279 item.iItem = 1;
6280 item.iSubItem = 0;
6281 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6282 ok(ret == 1, "got %d\n", ret);
6283 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused1_seq, "insert focused 1", FALSE);
6285 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
6286 ok(state == LVIS_FOCUSED, "got %x\n", state);
6288 /* insert item 2, no focus shift */
6289 item.mask = LVIF_STATE;
6290 item.state = 0;
6291 item.stateMask = LVIS_FOCUSED;
6292 item.iItem = 2;
6293 item.iSubItem = 0;
6294 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6295 ok(ret == 2, "got %d\n", ret);
6296 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert focused 2", FALSE);
6298 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
6299 ok(state == LVIS_FOCUSED, "got %x\n", state);
6301 /* insert item 3 */
6302 item.mask = LVIF_STATE | LVIF_PARAM;
6303 item.state = LVIS_SELECTED;
6304 item.stateMask = LVIS_SELECTED;
6305 item.iItem = 3;
6306 item.iSubItem = 0;
6307 item.lParam = 0xdeadbeef;
6308 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6309 ok(ret == 3, "got %d\n", ret);
6310 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_selected_seq, "insert selected", FALSE);
6312 /* insert item 4 */
6313 item.mask = LVIF_PARAM;
6314 item.state = 0;
6315 item.stateMask = 0;
6316 item.iItem = 4;
6317 item.iSubItem = 0;
6318 item.lParam = 0xdeadbeef;
6319 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6320 ok(ret == 4, "got %d\n", ret);
6321 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert param", FALSE);
6323 /* insert item 5 */
6324 item.mask = LVIF_STATE;
6325 item.state = 0;
6326 item.stateMask = 0;
6327 item.iItem = 5;
6328 item.iSubItem = 0;
6329 item.lParam = 0xdeadbeef;
6330 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6331 ok(ret == 5, "got %d\n", ret);
6332 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert state", FALSE);
6334 DestroyWindow(hwnd);
6337 static void test_header_proc(void)
6339 HWND hwnd, header, hdr;
6340 WNDPROC proc1, proc2;
6342 hwnd = create_listview_control(LVS_REPORT);
6344 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6345 ok(header != NULL, "got %p\n", header);
6347 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
6348 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
6349 0, 0, 0, 0,
6350 NULL, NULL, NULL, NULL);
6351 ok(hdr != NULL, "got %p\n", hdr);
6353 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
6354 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
6355 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
6357 DestroyWindow(hdr);
6358 DestroyWindow(hwnd);
6361 static void flush_events(void)
6363 MSG msg;
6364 int diff = 200;
6365 int min_timeout = 100;
6366 DWORD time = GetTickCount() + diff;
6368 while (diff > 0)
6370 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
6371 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6372 diff = time - GetTickCount();
6376 static void test_oneclickactivate(void)
6378 TRACKMOUSEEVENT track;
6379 char item1[] = "item1";
6380 LVITEMA item;
6381 HWND hwnd, fg;
6382 RECT rect;
6383 INT r;
6384 POINT orig_pos;
6386 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
6387 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
6388 ok(hwnd != NULL, "failed to create listview window\n");
6389 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
6390 ok(r == 0, "should return zero\n");
6392 SetForegroundWindow(hwndparent);
6393 flush_events();
6394 fg = GetForegroundWindow();
6395 if (fg != hwndparent)
6397 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
6398 DestroyWindow(hwnd);
6399 return;
6402 item.mask = LVIF_TEXT;
6403 item.iItem = 0;
6404 item.iSubItem = 0;
6405 item.iImage = 0;
6406 item.pszText = item1;
6407 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
6408 ok(r == 0, "should not fail\n");
6410 GetWindowRect(hwnd, &rect);
6411 GetCursorPos(&orig_pos);
6412 SetCursorPos(rect.left+5, rect.top+5);
6413 flush_events();
6414 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
6415 expect(0, r);
6417 track.cbSize = sizeof(track);
6418 track.dwFlags = TME_QUERY;
6419 p_TrackMouseEvent(&track);
6420 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
6421 ok(track.dwFlags == TME_LEAVE, "dwFlags = %lx\n", track.dwFlags);
6423 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
6424 expect(0, r);
6425 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
6426 expect(0, r);
6427 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
6428 expect(1, r);
6430 DestroyWindow(hwnd);
6431 SetCursorPos(orig_pos.x, orig_pos.y);
6434 static void test_callback_mask(void)
6436 LVITEMA item;
6437 DWORD mask;
6438 HWND hwnd;
6439 BOOL ret;
6441 hwnd = create_listview_control(LVS_REPORT);
6443 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 0);
6444 ok(ret, "got %d\n", ret);
6446 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 1);
6447 ok(ret, "got %d\n", ret);
6449 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6450 ok(mask == ~0u, "got 0x%08lx\n", mask);
6452 /* Ask for state, invalid subitem. */
6453 insert_item(hwnd, 0);
6455 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
6456 ok(ret, "Failed to set callback mask.\n");
6458 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6460 memset(&item, 0, sizeof(item));
6461 item.iSubItem = 1;
6462 item.mask = LVIF_STATE;
6463 item.stateMask = LVIS_SELECTED;
6464 ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6465 ok(ret, "Failed to get item data.\n");
6467 memset(&item, 0, sizeof(item));
6468 item.mask = LVIF_STATE;
6469 item.stateMask = LVIS_SELECTED;
6470 ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6471 ok(ret, "Failed to get item data.\n");
6473 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, callback mask/invalid subitem 1", TRUE);
6475 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6477 memset(&item, 0, sizeof(item));
6478 memset(&g_itema, 0, sizeof(g_itema));
6479 item.iSubItem = 1;
6480 item.mask = LVIF_STATE;
6481 item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
6482 ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6483 ok(ret, "Failed to get item data.\n");
6484 ok(g_itema.iSubItem == 1, "Unexpected LVN_DISPINFO subitem %d.\n", g_itema.iSubItem);
6485 ok(g_itema.stateMask == LVIS_FOCUSED, "Unexpected state mask %#x.\n", g_itema.stateMask);
6487 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
6488 "parent seq, callback mask/invalid subitem 2", FALSE);
6490 DestroyWindow(hwnd);
6492 /* LVS_OWNERDATA, mask LVIS_FOCUSED */
6493 hwnd = create_listview_control(LVS_REPORT | LVS_OWNERDATA);
6495 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6496 ok(mask == 0, "Unexpected callback mask %#lx.\n", mask);
6498 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
6499 ok(ret, "Failed to set callback mask, %d\n", ret);
6501 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6502 ok(mask == LVIS_FOCUSED, "Unexpected callback mask %#lx.\n", mask);
6504 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6505 ok(ret, "Failed to set item count.\n");
6507 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6508 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6510 item.stateMask = LVIS_FOCUSED;
6511 item.state = LVIS_FOCUSED;
6512 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6513 ok(ret, "Failed to set item state.\n");
6515 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6517 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6518 todo_wine
6519 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6521 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6522 todo_wine
6523 ok(ret == 0, "Unexpected selection mark, %d\n", ret);
6525 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
6526 ok(ret, "Failed to set item count.\n");
6528 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6529 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6531 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6532 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6534 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6535 ok(ret, "Failed to set item count.\n");
6537 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6538 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6540 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 1", FALSE);
6542 /* LVS_OWNDERDATA, empty mask */
6543 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, 0, 0);
6544 ok(ret, "Failed to set callback mask, %d\n", ret);
6546 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6547 ok(ret, "Failed to set item count.\n");
6549 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6550 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6552 item.stateMask = LVIS_FOCUSED;
6553 item.state = LVIS_FOCUSED;
6554 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6555 ok(ret, "Failed to set item state.\n");
6557 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6558 ok(ret == 0, "Unexpected selection mark, %d\n", ret);
6560 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6562 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6563 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6565 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
6566 ok(ret, "Failed to set item count.\n");
6568 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6569 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6571 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6572 todo_wine
6573 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6575 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6576 ok(ret, "Failed to set item count.\n");
6578 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6579 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6581 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 2", FALSE);
6583 /* 2 items, focus on index 0, reduce to 1 item. */
6584 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6586 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 2, 0);
6587 ok(ret, "Failed to set item count.\n");
6589 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6590 ok(ret, "Failed to set item state.\n");
6592 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6593 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6595 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6596 ok(ret, "Failed to set item count.\n");
6598 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6599 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6601 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_focus_change_ownerdata_seq,
6602 "parent seq, owner data/focus 3", TRUE);
6604 DestroyWindow(hwnd);
6607 static void test_state_image(void)
6609 static const DWORD styles[] =
6611 LVS_ICON,
6612 LVS_REPORT,
6613 LVS_SMALLICON,
6614 LVS_LIST,
6616 int i;
6618 for (i = 0; i < ARRAY_SIZE(styles); i++)
6620 static char text[] = "Item";
6621 static char subtext[] = "Subitem";
6622 char buff[16];
6623 LVITEMA item;
6624 HWND hwnd;
6625 int r;
6627 hwnd = create_listview_control(styles[i]);
6629 insert_column(hwnd, 0);
6630 insert_column(hwnd, 1);
6632 item.mask = LVIF_TEXT | LVIF_PARAM;
6633 item.iItem = 0;
6634 item.iSubItem = 0;
6635 item.pszText = text;
6636 item.lParam = 123456;
6637 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6638 ok(r == 0, "Failed to insert an item.\n");
6640 item.mask = LVIF_STATE;
6641 item.state = INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED;
6642 item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED | LVIS_FOCUSED;
6643 item.iItem = 0;
6644 item.iSubItem = 0;
6645 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6646 ok(r, "Failed to set item state.\n");
6648 item.mask = LVIF_TEXT;
6649 item.iItem = 0;
6650 item.iSubItem = 1;
6651 item.pszText = subtext;
6652 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6653 ok(r, "Failed to set subitem text.\n");
6655 item.mask = LVIF_STATE | LVIF_PARAM;
6656 item.stateMask = ~0u;
6657 item.state = 0;
6658 item.iItem = 0;
6659 item.iSubItem = 0;
6660 item.lParam = 0;
6661 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6662 ok(r, "Failed to get item state.\n");
6663 ok(item.state == (INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED),
6664 "Unexpected item state %#x.\n", item.state);
6665 ok(item.lParam == 123456, "Unexpected lParam %Id.\n", item.lParam);
6667 item.mask = 0;
6668 item.stateMask = ~0u;
6669 item.state = INDEXTOSTATEIMAGEMASK(2);
6670 item.iItem = 0;
6671 item.iSubItem = 1;
6672 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6673 ok(r, "Failed to get subitem state.\n");
6674 ok(item.state == INDEXTOSTATEIMAGEMASK(2), "Unexpected state %#x.\n", item.state);
6676 item.mask = LVIF_STATE | LVIF_PARAM;
6677 item.stateMask = ~0u;
6678 item.state = INDEXTOSTATEIMAGEMASK(2);
6679 item.iItem = 0;
6680 item.iSubItem = 1;
6681 item.lParam = 0;
6682 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6683 ok(r, "Failed to get subitem state.\n");
6684 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6685 ok(item.lParam == 123456, "Unexpected lParam %Id.\n", item.lParam);
6687 item.mask = LVIF_STATE;
6688 item.stateMask = LVIS_FOCUSED;
6689 item.state = 0;
6690 item.iItem = 0;
6691 item.iSubItem = 1;
6692 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6693 ok(r, "Failed to get subitem state.\n");
6694 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6696 item.mask = LVIF_STATE;
6697 item.stateMask = ~0u;
6698 item.state = INDEXTOSTATEIMAGEMASK(2);
6699 item.iItem = 0;
6700 item.iSubItem = 2;
6701 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6702 ok(r, "Failed to get subitem state.\n");
6703 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6705 item.mask = LVIF_TEXT;
6706 item.iItem = 0;
6707 item.iSubItem = 1;
6708 item.pszText = buff;
6709 item.cchTextMax = sizeof(buff);
6710 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6711 ok(r, "Failed to get subitem text %d.\n", r);
6712 ok(!strcmp(buff, subtext), "Unexpected subitem text %s.\n", buff);
6714 DestroyWindow(hwnd);
6718 static void test_LVSCW_AUTOSIZE(void)
6720 int width, width2;
6721 HWND hwnd;
6722 BOOL ret;
6724 hwnd = create_listview_control(LVS_REPORT);
6725 ok(hwnd != NULL, "failed to create a listview window\n");
6727 insert_column(hwnd, 0);
6728 insert_column(hwnd, 1);
6729 insert_item(hwnd, 0);
6731 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6732 ok(ret, "Failed to set column width.\n");
6734 width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6735 ok(width > 0, "Unexpected column width %d.\n", width);
6737 /* Turn on checkboxes. */
6738 ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
6739 ok(ret == 0, "Unexpected previous extended style.\n");
6741 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6742 ok(ret, "Failed to set column width.\n");
6744 width2 = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6745 ok(width2 > 0, "Unexpected column width %d.\n", width2);
6746 ok(width2 > width, "Expected increased column width.\n");
6748 /* Turn off checkboxes. */
6749 ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
6750 ok(ret == LVS_EX_CHECKBOXES, "Unexpected previous extended style.\n");
6752 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6753 ok(ret, "Failed to set column width.\n");
6755 width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6756 ok(width > 0, "Unexpected column width %d.\n", width2);
6757 ok(width2 > width, "Expected reduced column width.\n");
6759 DestroyWindow(hwnd);
6762 static void test_LVN_ENDLABELEDIT(void)
6764 WCHAR text[] = {'l','a','l','a',0};
6765 HWND hwnd, hwndedit;
6766 LVITEMW item = {0};
6767 DWORD ret;
6769 hwnd = create_listview_control(LVS_REPORT | LVS_EDITLABELS);
6771 insert_column(hwnd, 0);
6773 item.mask = LVIF_TEXT;
6774 item.pszText = text;
6775 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
6777 /* Test normal editing */
6778 SetFocus(hwnd);
6779 hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
6780 ok(hwndedit != NULL, "Failed to get edit control.\n");
6782 ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test");
6783 ok(ret, "Failed to set edit text.\n");
6785 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6787 ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
6788 ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit, "Label edit", FALSE);
6790 /* Test editing with kill focus */
6791 SetFocus(hwnd);
6792 hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
6793 ok(hwndedit != NULL, "Failed to get edit control.\n");
6795 ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test2");
6796 ok(ret, "Failed to set edit text.\n");
6798 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6800 g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = TRUE;
6801 ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
6802 g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = FALSE;
6804 ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit_kill_focus,
6805 "Label edit, kill focus", FALSE);
6806 ok(GetFocus() == hwnd, "Unexpected focused window.\n");
6808 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6810 DestroyWindow(hwnd);
6813 static LRESULT CALLBACK create_item_height_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
6815 if (msg == WM_CREATE)
6816 return 0;
6818 return CallWindowProcA(listviewWndProc, hwnd, msg, wParam, lParam);
6821 static void test_LVM_GETCOUNTPERPAGE(void)
6823 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
6824 unsigned int i, j;
6825 WNDCLASSEXA cls;
6826 ATOM class;
6827 HWND hwnd;
6828 BOOL ret;
6830 cls.cbSize = sizeof(WNDCLASSEXA);
6831 ret = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
6832 ok(ret, "Failed to get class info.\n");
6833 listviewWndProc = cls.lpfnWndProc;
6834 cls.lpfnWndProc = create_item_height_wndproc;
6835 cls.lpszClassName = "CountPerPageClass";
6836 class = RegisterClassExA(&cls);
6837 ok(class, "Failed to register class.\n");
6839 for (i = 0; i < ARRAY_SIZE(styles); i++)
6841 static char text[] = "item text";
6842 LVITEMA item = { 0 };
6843 UINT count, count2;
6845 hwnd = create_listview_control(styles[i]);
6846 ok(hwnd != NULL, "Failed to create listview window.\n");
6848 count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6849 if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
6850 ok(count > 0 || broken(styles[i] == LVS_LIST && count == 0), "%u: unexpected count %u.\n", i, count);
6851 else
6852 ok(count == 0, "%u: unexpected count %u.\n", i, count);
6854 for (j = 0; j < 10; j++)
6856 item.mask = LVIF_TEXT;
6857 item.pszText = text;
6858 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6861 count2 = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6862 if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
6863 ok(count == count2, "%u: unexpected count %u.\n", i, count2);
6864 else
6865 ok(count2 == 10, "%u: unexpected count %u.\n", i, count2);
6867 DestroyWindow(hwnd);
6869 hwnd = CreateWindowA("CountPerPageClass", "Test", WS_VISIBLE | styles[i], 0, 0, 100, 100, NULL, NULL,
6870 GetModuleHandleA(NULL), 0);
6871 ok(hwnd != NULL, "Failed to create a window.\n");
6873 count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6874 ok(count == 0, "%u: unexpected count %u.\n", i, count);
6876 DestroyWindow(hwnd);
6879 ret = UnregisterClassA("CountPerPageClass", NULL);
6880 ok(ret, "Failed to unregister test class.\n");
6883 static void test_item_state_change(void)
6885 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
6886 LVITEMA item;
6887 HWND hwnd;
6888 DWORD res;
6889 int i;
6891 for (i = 0; i < ARRAY_SIZE(styles); i++)
6893 hwnd = create_listview_control(styles[i]);
6895 insert_item(hwnd, 0);
6897 /* LVM_SETITEMSTATE with mask */
6898 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6899 memset(&item, 0, sizeof(item));
6900 item.mask = LVIF_STATE;
6901 item.stateMask = LVIS_SELECTED;
6902 item.state = LVIS_SELECTED;
6903 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6904 ok(res, "Failed to set item state.\n");
6906 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6907 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6908 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
6909 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
6910 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
6911 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
6913 /* LVM_SETITEMSTATE 0 mask */
6914 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6915 memset(&item, 0, sizeof(item));
6916 item.stateMask = LVIS_SELECTED;
6917 item.state = 0;
6918 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6919 ok(res, "Failed to set item state.\n");
6921 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6922 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6923 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
6924 ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
6925 ok(g_nmlistview.uOldState == LVIS_SELECTED, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
6926 ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
6928 /* LVM_SETITEM changes state */
6929 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6930 memset(&item, 0, sizeof(item));
6931 item.stateMask = LVIS_SELECTED;
6932 item.state = LVIS_SELECTED;
6933 item.mask = LVIF_STATE;
6934 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6935 ok(res, "Failed to set item.\n");
6937 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6938 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6939 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
6940 ok(g_nmlistview.uNewState == LVIS_SELECTED, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
6941 ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
6942 ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
6944 /* LVM_SETITEM no state changes */
6945 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6946 memset(&item, 0, sizeof(item));
6947 item.lParam = 11;
6948 item.mask = LVIF_PARAM;
6949 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6950 ok(res, "Failed to set item.\n");
6952 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6953 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6954 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
6955 ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
6956 ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
6957 ok(g_nmlistview.uChanged == LVIF_PARAM, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
6959 DestroyWindow(hwnd);
6963 static void test_selected_column(void)
6965 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
6966 int ret, i;
6967 HWND hwnd;
6969 for (i = 0; i < ARRAY_SIZE(styles); ++i)
6971 hwnd = create_listview_control(styles[i]);
6973 /* Initial value */
6974 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
6975 ok(ret == -1, "Unexpected column %d.\n", ret);
6977 ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, -100, 0);
6978 ok(ret == 1, "Unexpected return value %d.\n", ret);
6980 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
6981 ok(ret == -100, "Unexpected column %d.\n", ret);
6983 ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, 100, 0);
6984 ok(ret == 1, "Unexpected return value %d.\n", ret);
6986 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
6987 ok(ret == 100, "Unexpected column %d.\n", ret);
6989 ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, -1, 0);
6990 ok(ret == 1, "Unexpected return value %d.\n", ret);
6992 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
6993 ok(ret == -1, "Unexpected column %d.\n", ret);
6995 DestroyWindow(hwnd);
6999 static void test_LVM_GETNEXTITEMINDEX(void)
7001 LVITEMINDEX index;
7002 HWND hwnd;
7003 BOOL ret;
7005 hwnd = create_listview_control(LVS_REPORT);
7007 insert_item(hwnd, 0);
7008 insert_item(hwnd, 1);
7010 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, 0, LVNI_ALL);
7011 ok(!ret, "Unexpected return value %d.\n", ret);
7013 index.iItem = -1;
7014 index.iGroup = 0;
7015 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
7016 ok(ret, "Unexpected return value %d.\n", ret);
7017 ok(index.iItem == 0, "Unexpected item index %d.\n", index.iItem);
7019 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
7020 ok(ret, "Unexpected return value %d.\n", ret);
7021 ok(index.iItem == 1, "Unexpected item index %d.\n", index.iItem);
7023 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
7024 ok(!ret, "Unexpected return value %d.\n", ret);
7025 ok(index.iItem == -1, "Unexpected item index %d.\n", index.iItem);
7027 DestroyWindow(hwnd);
7030 static void test_LVM_SETBKIMAGE(BOOL is_v6)
7032 LVBKIMAGEA image;
7033 HBITMAP hbmp;
7034 BITMAP bm;
7035 HWND hwnd;
7036 int ret;
7038 CoInitialize(NULL);
7040 hbmp = CreateBitmap(32, 32, 1, 1, NULL);
7041 hwnd = create_listview_control(LVS_REPORT);
7043 image.ulFlags = LVBKIF_SOURCE_NONE;
7044 image.hbm = 0;
7045 image.pszImage = NULL;
7046 image.cchImageMax = 0;
7047 image.xOffsetPercent = 0;
7048 image.yOffsetPercent = 0;
7049 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7050 ok(!ret, "got %d\n", ret);
7052 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7053 ok(ret == sizeof(bm), "got %d\n", ret);
7055 image.ulFlags = LVBKIF_SOURCE_HBITMAP;
7056 image.hbm = hbmp;
7057 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7058 if (is_v6)
7059 ok(ret, "got %d\n", ret);
7060 else
7061 todo_wine ok(!ret, "got %d\n", ret);
7063 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7064 ok(ret == sizeof(bm), "got %d\n", ret);
7066 image.ulFlags = LVBKIF_SOURCE_NONE;
7067 image.hbm = 0;
7068 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7069 ok(!ret, "got %d\n", ret);
7071 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7072 ok(!ret, "got %d\n", ret);
7074 hbmp = CreateBitmap(32, 32, 1, 1, NULL);
7076 image.ulFlags = LVBKIF_SOURCE_HBITMAP;
7077 image.hbm = hbmp;
7078 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7079 if (is_v6)
7080 ok(ret, "got %d\n", ret);
7081 else
7082 todo_wine ok(!ret, "got %d\n", ret);
7084 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7085 ok(ret == sizeof(bm), "got %d\n", ret);
7087 image.ulFlags = LVBKIF_SOURCE_HBITMAP;
7088 image.hbm = hbmp;
7089 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7090 ok(!ret, "got %d\n", ret);
7092 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7093 ok(!ret, "got %d\n", ret);
7095 image.ulFlags = LVBKIF_SOURCE_NONE;
7096 image.hbm = 0;
7097 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7098 ok(!ret, "got %d\n", ret);
7100 DestroyWindow(hwnd);
7102 CoUninitialize();
7105 START_TEST(listview)
7107 ULONG_PTR ctx_cookie;
7108 HANDLE hCtx;
7110 init_functions();
7112 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
7114 hwndparent = create_parent_window(FALSE);
7115 flush_sequences(sequences, NUM_MSG_SEQUENCES);
7117 test_header_notification();
7118 test_header_notification2();
7119 test_images();
7120 test_checkboxes();
7121 test_items();
7122 test_create(FALSE);
7123 test_redraw();
7124 test_customdraw();
7125 test_icon_spacing();
7126 test_color();
7127 test_item_count();
7128 test_item_position();
7129 test_columns();
7130 test_getorigin();
7131 test_multiselect();
7132 test_getitemrect();
7133 test_subitem_rect();
7134 test_sorting();
7135 test_ownerdata();
7136 test_ownerdata_multiselect();
7137 test_norecompute();
7138 test_nosortheader();
7139 test_setredraw();
7140 test_hittest();
7141 test_getviewrect();
7142 test_getitemposition();
7143 test_editbox();
7144 test_notifyformat();
7145 test_indentation();
7146 test_getitemspacing();
7147 test_getcolumnwidth();
7148 test_approximate_viewrect();
7149 test_finditem();
7150 test_hover();
7151 test_destroynotify();
7152 test_createdragimage();
7153 test_dispinfo();
7154 test_LVM_SETITEMTEXT();
7155 test_LVM_REDRAWITEMS();
7156 test_imagelists();
7157 test_deleteitem();
7158 test_insertitem();
7159 test_LVM_INSERTITEM();
7160 test_header_proc();
7161 test_oneclickactivate();
7162 test_callback_mask();
7163 test_state_image();
7164 test_LVSCW_AUTOSIZE();
7165 test_LVN_ENDLABELEDIT();
7166 test_LVM_GETCOUNTPERPAGE();
7167 test_item_state_change();
7168 test_LVM_SETBKIMAGE(FALSE);
7170 if (!load_v6_module(&ctx_cookie, &hCtx))
7172 DestroyWindow(hwndparent);
7173 return;
7176 init_functions();
7178 /* comctl32 version 6 tests start here */
7179 test_get_set_view();
7180 test_canceleditlabel();
7181 test_mapidindex();
7182 test_scrollnotify();
7183 test_LVS_EX_TRANSPARENTBKGND();
7184 test_LVS_EX_HEADERINALLVIEWS();
7185 test_deleteitem();
7186 test_multiselect();
7187 test_insertitem();
7188 test_header_proc();
7189 test_images();
7190 test_checkboxes();
7191 test_items();
7192 test_create(TRUE);
7193 test_color();
7194 test_columns();
7195 test_sorting();
7196 test_ownerdata();
7197 test_ownerdata_multiselect();
7198 test_norecompute();
7199 test_nosortheader();
7200 test_indentation();
7201 test_finditem();
7202 test_hover();
7203 test_destroynotify();
7204 test_createdragimage();
7205 test_dispinfo();
7206 test_LVM_SETITEMTEXT();
7207 test_LVM_REDRAWITEMS();
7208 test_oneclickactivate();
7209 test_state_image();
7210 test_LVSCW_AUTOSIZE();
7211 test_LVN_ENDLABELEDIT();
7212 test_LVM_GETCOUNTPERPAGE();
7213 test_item_state_change();
7214 test_selected_column();
7215 test_LVM_GETNEXTITEMINDEX();
7216 test_LVM_SETBKIMAGE(TRUE);
7218 unload_v6_module(ctx_cookie, hCtx);
7220 DestroyWindow(hwndparent);