include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / comctl32 / tests / listview.c
blob1081a045cde5110818731820ae09c52f30e04c96
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_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
119 { 0 }
122 static const struct message listview_icon_spacing_seq[] = {
123 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
124 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
125 { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
126 { 0 }
129 static const struct message listview_color_seq[] = {
130 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
131 { LVM_GETBKCOLOR, sent },
132 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
133 { LVM_GETTEXTCOLOR, sent },
134 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
135 { LVM_GETTEXTBKCOLOR, sent },
137 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
138 { LVM_GETBKCOLOR, sent },
139 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
140 { LVM_GETTEXTCOLOR, sent },
141 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
142 { LVM_GETTEXTBKCOLOR, sent },
144 { LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
145 { LVM_GETBKCOLOR, sent },
146 { LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
147 { LVM_GETTEXTCOLOR, sent },
148 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
149 { LVM_GETTEXTBKCOLOR, sent },
151 { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
152 { LVM_GETBKCOLOR, sent },
153 { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
154 { LVM_GETTEXTCOLOR, sent },
155 { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
156 { LVM_GETTEXTBKCOLOR, sent },
157 { 0 }
160 static const struct message listview_item_count_seq[] = {
161 { LVM_GETITEMCOUNT, sent },
162 { LVM_INSERTITEMA, sent },
163 { LVM_INSERTITEMA, sent },
164 { LVM_INSERTITEMA, sent },
165 { LVM_GETITEMCOUNT, sent },
166 { LVM_DELETEITEM, sent|wparam, 2 },
167 { WM_NCPAINT, sent|optional },
168 { WM_ERASEBKGND, sent|optional },
169 { LVM_GETITEMCOUNT, sent },
170 { LVM_DELETEALLITEMS, sent },
171 { LVM_GETITEMCOUNT, sent },
172 { LVM_INSERTITEMA, sent },
173 { LVM_INSERTITEMA, sent },
174 { LVM_GETITEMCOUNT, sent },
175 { LVM_INSERTITEMA, sent },
176 { LVM_GETITEMCOUNT, sent },
177 { 0 }
180 static const struct message listview_itempos_seq[] = {
181 { LVM_INSERTITEMA, sent },
182 { LVM_INSERTITEMA, sent },
183 { LVM_INSERTITEMA, sent },
184 { LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
185 { WM_NCPAINT, sent|optional },
186 { WM_ERASEBKGND, sent|optional },
187 { LVM_GETITEMPOSITION, sent|wparam, 1 },
188 { LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
189 { LVM_GETITEMPOSITION, sent|wparam, 2 },
190 { LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
191 { LVM_GETITEMPOSITION, sent|wparam, 0 },
192 { 0 }
195 static const struct message listview_ownerdata_switchto_seq[] = {
196 { WM_STYLECHANGING, sent },
197 { WM_STYLECHANGED, sent },
198 { 0 }
201 static const struct message listview_getorderarray_seq[] = {
202 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
203 { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
204 { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
205 { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
206 { 0 }
209 static const struct message listview_setorderarray_seq[] = {
210 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
211 { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
212 { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID },
213 { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
214 { 0 }
217 static const struct message empty_seq[] = {
218 { 0 }
221 static const struct message parent_focus_change_ownerdata_seq[] = {
222 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
223 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
224 { 0 }
227 static const struct message forward_erasebkgnd_parent_seq[] = {
228 { WM_ERASEBKGND, sent },
229 { 0 }
232 static const struct message ownerdata_select_focus_parent_seq[] = {
233 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
234 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
235 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
236 { 0 }
239 static const struct message ownerdata_setstate_all_parent_seq[] = {
240 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
241 { 0 }
244 static const struct message ownerdata_defocus_all_parent_seq[] = {
245 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
246 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
247 { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
248 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
249 { 0 }
252 static const struct message ownerdata_deselect_all_parent_seq[] = {
253 { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
254 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
255 { 0 }
258 static const struct message ownerdata_multiselect_select_0_to_1_odstatechanged_seq[] = {
259 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
260 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
261 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
262 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
263 { 0 }
266 static const struct message ownerdata_multiselect_select_0_odstatechanged_seq[] = {
267 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
268 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
269 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
270 { 0 }
273 static const struct message ownerdata_multiselect_select_0_modkey_odstatechanged_seq[] = {
274 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
275 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
276 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
277 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
278 { 0 }
281 static const struct message ownerdata_multiselect_move_0_to_1_odstatechanged_seq[] = {
282 { WM_NOTIFY, sent|id|wparam, 0, 0, LVN_ITEMCHANGED },
283 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
284 { 0 }
287 static const struct message ownerdata_multiselect_select_0_to_2_odstatechanged_seq[] = {
288 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
289 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
290 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
291 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
292 { 0 }
295 static const struct message ownerdata_multiselect_select_3_odstatechanged_seq[] = {
296 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
297 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
298 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
299 { 0 }
302 static const struct message ownerdata_multiselect_select_3_modkey_odstatechanged_seq[] = {
303 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
304 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
305 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
306 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
307 { 0 }
310 static const struct message ownerdata_multiselect_select_3_to_2_odstatechanged_seq[] = {
311 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
312 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
313 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
314 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
315 { 0 }
318 static const struct message ownerdata_multiselect_move_3_to_2_odstatechanged_seq[] = {
319 { WM_NOTIFY, sent|id|wparam, 3, 0, LVN_ITEMCHANGED },
320 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
321 { 0 }
324 static const struct message ownerdata_multiselect_select_3_to_1_odstatechanged_seq[] = {
325 { WM_NOTIFY, sent|id|wparam, -1, 0, LVN_ITEMCHANGED },
326 { WM_NOTIFY, sent|id, 0, 0, LVN_ODSTATECHANGED },
327 { WM_NOTIFY, sent|id|wparam, 2, 0, LVN_ITEMCHANGED },
328 { WM_NOTIFY, sent|id|wparam, 1, 0, LVN_ITEMCHANGED },
329 { 0 }
332 static const struct message change_all_parent_seq[] = {
333 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
334 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
336 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
337 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
339 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
340 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
342 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
343 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
345 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
346 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
347 { 0 }
350 static const struct message changing_all_parent_seq[] = {
351 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
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 { 0 }
359 static const struct message textcallback_set_again_parent_seq[] = {
360 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
361 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
362 { 0 }
365 static const struct message single_getdispinfo_parent_seq[] = {
366 { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
367 { 0 }
370 static const struct message getitemposition_seq1[] = {
371 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
372 { 0 }
375 static const struct message getitemposition_seq2[] = {
376 { LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
377 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
378 { 0 }
381 static const struct message getsubitemrect_seq[] = {
382 { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
383 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
384 { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
385 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
386 { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
387 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
388 { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
389 { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
390 { 0 }
393 static const struct message editbox_create_pos[] = {
394 /* sequence sent after LVN_BEGINLABELEDIT */
395 /* next two are 4.7x specific */
396 { WM_WINDOWPOSCHANGING, sent },
397 { WM_WINDOWPOSCHANGED, sent|optional },
399 { WM_WINDOWPOSCHANGING, sent|optional },
400 { WM_NCCALCSIZE, sent },
401 { WM_WINDOWPOSCHANGED, sent },
402 { WM_MOVE, sent|defwinproc },
403 { WM_SIZE, sent|defwinproc },
404 /* the rest is todo, skipped in 4.7x */
405 { WM_WINDOWPOSCHANGING, sent|optional },
406 { WM_WINDOWPOSCHANGED, sent|optional },
407 { 0 }
410 static const struct message scroll_parent_seq[] = {
411 { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
412 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
413 { 0 }
416 static const struct message setredraw_seq[] = {
417 { WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
418 { 0 }
421 static const struct message lvs_ex_transparentbkgnd_seq[] = {
422 { WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
423 { 0 }
426 static const struct message edit_end_nochange[] = {
427 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
428 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
429 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
430 { 0 }
433 static const struct message hover_parent[] = {
434 { WM_GETDLGCODE, sent }, /* todo_wine */
435 { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
436 { 0 }
439 static const struct message listview_destroy[] = {
440 { 0x0090, sent|optional }, /* Vista */
441 { WM_PARENTNOTIFY, sent },
442 { WM_SHOWWINDOW, sent },
443 { WM_WINDOWPOSCHANGING, sent },
444 { WM_WINDOWPOSCHANGED, sent|optional },
445 { WM_DESTROY, sent },
446 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
447 { WM_NCDESTROY, sent },
448 { 0 }
451 static const struct message listview_ownerdata_destroy[] = {
452 { 0x0090, sent|optional }, /* Vista */
453 { WM_PARENTNOTIFY, sent },
454 { WM_SHOWWINDOW, sent },
455 { WM_WINDOWPOSCHANGING, sent },
456 { WM_WINDOWPOSCHANGED, sent|optional },
457 { WM_DESTROY, sent },
458 { WM_NCDESTROY, sent },
459 { 0 }
462 static const struct message listview_ownerdata_deleteall[] = {
463 { LVM_DELETEALLITEMS, sent },
464 { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
465 { 0 }
468 static const struct message listview_header_changed_seq[] = {
469 { LVM_SETCOLUMNA, sent },
470 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
471 { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
472 { 0 }
475 static const struct message parent_header_click_seq[] = {
476 { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
477 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
478 { 0 }
481 static const struct message parent_header_divider_dclick_seq[] = {
482 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
483 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
484 { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
485 { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
486 { WM_NOTIFY, sent|id, 0, 0, HDN_DIVIDERDBLCLICKA },
487 { 0 }
490 static const struct message listview_set_imagelist[] = {
491 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
492 { 0 }
495 static const struct message listview_header_set_imagelist[] = {
496 { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
497 { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
498 { 0 }
501 static const struct message parent_report_cd_seq[] = {
502 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
503 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
504 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
505 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
506 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM },
507 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM },
508 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
509 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
510 { 0 }
513 static const struct message parent_list_cd_seq[] = {
514 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
515 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
516 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
517 { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
518 { 0 }
521 static const struct message listview_end_label_edit[] = {
522 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
523 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING},
524 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
525 { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
526 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
527 { 0 }
530 static const struct message listview_end_label_edit_kill_focus[] = {
531 { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
532 { WM_COMMAND, sent|id|optional, 0, 0, EN_KILLFOCUS }, /* todo: not sent by wine yet */
533 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
534 { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
535 { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
536 { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
537 { 0 }
540 static void hold_key(int vk)
542 BYTE kstate[256];
543 BOOL res;
545 res = GetKeyboardState(kstate);
546 ok(res, "GetKeyboardState failed.\n");
547 kstate[vk] |= 0x80;
548 res = SetKeyboardState(kstate);
549 ok(res, "SetKeyboardState failed.\n");
552 static void release_key(int vk)
554 BYTE kstate[256];
555 BOOL res;
557 res = GetKeyboardState(kstate);
558 ok(res, "GetKeyboardState failed.\n");
559 kstate[vk] &= ~0x80;
560 res = SetKeyboardState(kstate);
561 ok(res, "SetKeyboardState failed.\n");
564 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
566 static LONG defwndproc_counter = 0;
567 LRESULT ret;
568 struct message msg;
570 msg.message = message;
571 msg.flags = sent|wparam|lparam;
572 if (defwndproc_counter) msg.flags |= defwinproc;
573 msg.wParam = wParam;
574 msg.lParam = lParam;
575 if (message == WM_NOTIFY && lParam)
577 NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
579 msg.id = nmlv->hdr.code;
580 if (msg.id == LVN_ITEMCHANGING || msg.id == LVN_ITEMCHANGED)
582 msg.wParam = nmlv->iItem;
583 msg.lParam = nmlv->uChanged;
586 if (message == WM_COMMAND) msg.id = HIWORD(wParam);
588 /* log system messages, except for painting */
589 if (message < WM_USER &&
590 message != WM_PAINT &&
591 message != WM_ERASEBKGND &&
592 message != WM_NCPAINT &&
593 message != WM_NCHITTEST &&
594 message != WM_GETTEXT &&
595 message != WM_GETICON &&
596 message != WM_DEVICECHANGE)
598 add_message(sequences, PARENT_SEQ_INDEX, &msg);
599 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
601 /* log change messages for single and multiple items changing in ownerdata listviews */
602 if (message == WM_NOTIFY && (msg.id == LVN_ITEMCHANGED || msg.id == LVN_ODSTATECHANGED))
603 add_message(sequences, PARENT_ODSTATECHANGED_SEQ_INDEX, &msg);
605 add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
607 switch (message)
609 case WM_NOTIFY:
611 switch (((NMHDR*)lParam)->code)
613 case LVN_BEGINLABELEDITA:
615 HWND edit = NULL;
617 /* subclass edit box */
618 if (!blockEdit)
619 edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
621 if (edit)
623 INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
624 ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
625 "text limit %d, expected 259\n", len);
628 return blockEdit;
630 case LVN_ENDLABELEDITA:
632 HWND edit;
634 /* always accept new item text */
635 NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
636 g_editbox_disp_info = *di;
638 /* edit control still available from this notification */
639 edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
640 ok(IsWindow(edit), "expected valid edit control handle\n");
641 ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
643 if (g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT)
644 SendMessageA(edit, WM_KILLFOCUS, 0, 0);
646 return TRUE;
648 case LVN_ITEMCHANGING:
650 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
651 g_nmlistview_changing = *nmlv;
653 break;
654 case LVN_ITEMCHANGED:
656 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
657 g_nmlistview = *nmlv;
659 break;
660 case LVN_GETDISPINFOA:
662 NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
663 g_itema = dispinfo->item;
665 if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
667 dispinfo->hdr.code = LVN_GETDISPINFOW;
668 lstrcpyW((WCHAR *)dispinfo->item.pszText, L"TEST");
671 /* test control buffer size for text, 10 used to mask cases when control
672 is using caller buffer to process LVM_GETITEM for example */
673 if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
674 ok(dispinfo->item.cchTextMax == 260 ||
675 broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
676 "buffer size %d\n", dispinfo->item.cchTextMax);
678 break;
679 case LVN_DELETEITEM:
680 if (g_focus_test_LVN_DELETEITEM)
682 NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
683 UINT state;
685 state = SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETITEMSTATE, nmlv->iItem, LVIS_FOCUSED);
686 ok(state == 0, "got state %x\n", state);
688 break;
689 case NM_HOVER:
690 if (g_block_hover) return 1;
691 break;
693 break;
695 case WM_NOTIFYFORMAT:
697 /* force to return format */
698 if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
699 break;
703 defwndproc_counter++;
704 if (IsWindowUnicode(hwnd))
705 ret = DefWindowProcW(hwnd, message, wParam, lParam);
706 else
707 ret = DefWindowProcA(hwnd, message, wParam, lParam);
708 defwndproc_counter--;
710 return ret;
713 static BOOL register_parent_wnd_class(BOOL Unicode)
715 WNDCLASSA clsA;
716 WNDCLASSW clsW;
718 if (Unicode)
720 clsW.style = 0;
721 clsW.lpfnWndProc = parent_wnd_proc;
722 clsW.cbClsExtra = 0;
723 clsW.cbWndExtra = 0;
724 clsW.hInstance = GetModuleHandleW(NULL);
725 clsW.hIcon = 0;
726 clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
727 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
728 clsW.lpszMenuName = NULL;
729 clsW.lpszClassName = L"Listview test parentW";
731 else
733 clsA.style = 0;
734 clsA.lpfnWndProc = parent_wnd_proc;
735 clsA.cbClsExtra = 0;
736 clsA.cbWndExtra = 0;
737 clsA.hInstance = GetModuleHandleA(NULL);
738 clsA.hIcon = 0;
739 clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
740 clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
741 clsA.lpszMenuName = NULL;
742 clsA.lpszClassName = "Listview test parent class";
745 return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
748 static HWND create_parent_window(BOOL Unicode)
750 HWND hwnd;
752 if (!register_parent_wnd_class(Unicode))
753 return NULL;
755 blockEdit = FALSE;
756 notifyFormat = -1;
758 if (Unicode)
759 hwnd = CreateWindowExW(0, L"Listview test parentW", L"testparentnameW",
760 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
761 WS_MAXIMIZEBOX | WS_VISIBLE,
762 0, 0, 100, 100,
763 GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
764 else
765 hwnd = CreateWindowExA(0, "Listview test parent class",
766 "Listview test parent window",
767 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
768 WS_MAXIMIZEBOX | WS_VISIBLE,
769 0, 0, 100, 100,
770 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
771 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
772 return hwnd;
775 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
777 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
778 static LONG defwndproc_counter = 0;
779 LRESULT ret;
780 struct message msg;
782 msg.message = message;
783 msg.flags = sent|wparam|lparam;
784 if (defwndproc_counter) msg.flags |= defwinproc;
785 msg.wParam = wParam;
786 msg.lParam = lParam;
787 msg.id = LISTVIEW_ID;
788 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
789 add_message(sequences, COMBINED_SEQ_INDEX, &msg);
791 defwndproc_counter++;
792 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
793 defwndproc_counter--;
794 return ret;
797 static HWND create_listview_control(DWORD style)
799 WNDPROC oldproc;
800 HWND hwnd;
801 RECT rect;
803 GetClientRect(hwndparent, &rect);
804 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
805 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
806 0, 0, rect.right, rect.bottom,
807 hwndparent, NULL, GetModuleHandleA(NULL), NULL);
808 ok(hwnd != NULL, "gle=%ld\n", GetLastError());
810 if (!hwnd) return NULL;
812 UpdateWindow(hwnd);
814 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
815 (LONG_PTR)listview_subclass_proc);
816 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
818 return hwnd;
821 /* unicode listview window with specified parent */
822 static HWND create_listview_controlW(DWORD style, HWND parent)
824 WNDPROC oldproc;
825 HWND hwnd;
826 RECT rect;
828 GetClientRect(parent, &rect);
829 hwnd = CreateWindowExW(0, WC_LISTVIEWW, L"foo",
830 WS_CHILD | WS_BORDER | WS_VISIBLE | style,
831 0, 0, rect.right, rect.bottom,
832 parent, NULL, GetModuleHandleW(NULL), NULL);
833 ok(hwnd != NULL, "gle=%ld\n", GetLastError());
835 if (!hwnd) return NULL;
837 UpdateWindow(hwnd);
839 oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
840 (LONG_PTR)listview_subclass_proc);
841 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
843 return hwnd;
847 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
849 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
850 static LONG defwndproc_counter = 0;
851 struct message msg = { 0 };
852 LRESULT ret;
854 msg.message = message;
855 msg.flags = sent|wparam|lparam;
856 if (defwndproc_counter) msg.flags |= defwinproc;
857 msg.wParam = wParam;
858 msg.lParam = lParam;
859 msg.id = HEADER_ID;
860 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
862 defwndproc_counter++;
863 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
864 defwndproc_counter--;
865 return ret;
868 static HWND subclass_header(HWND hwndListview)
870 WNDPROC oldproc;
871 HWND hwnd;
873 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
874 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
875 (LONG_PTR)header_subclass_proc);
876 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
878 return hwnd;
881 static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
883 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
884 static LONG defwndproc_counter = 0;
885 struct message msg = { 0 };
886 LRESULT ret;
888 msg.message = message;
889 msg.flags = sent|wparam|lparam;
890 if (defwndproc_counter) msg.flags |= defwinproc;
891 msg.wParam = wParam;
892 msg.lParam = lParam;
894 /* all we need is sizing */
895 if (message == WM_WINDOWPOSCHANGING ||
896 message == WM_NCCALCSIZE ||
897 message == WM_WINDOWPOSCHANGED ||
898 message == WM_MOVE ||
899 message == WM_SIZE)
901 add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
904 defwndproc_counter++;
905 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
906 defwndproc_counter--;
907 return ret;
910 static HWND subclass_editbox(HWND hwndListview)
912 WNDPROC oldproc;
913 HWND hwnd;
915 hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
916 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
917 (LONG_PTR)editbox_subclass_proc);
918 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
920 return hwnd;
923 /* Performs a single LVM_HITTEST test */
924 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
925 BOOL todo_item, BOOL todo_flags, int line)
927 LVHITTESTINFO lpht;
928 INT ret;
930 lpht.pt.x = x;
931 lpht.pt.y = y;
932 lpht.iSubItem = 10;
934 ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
936 todo_wine_if(todo_item)
938 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
939 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
940 ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
943 if (todo_flags)
945 todo_wine
946 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
948 else if (broken_flags)
949 ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
950 "Expected flags %x, got %x\n", flags, lpht.flags);
951 else
952 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
955 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
957 /* Performs a single LVM_SUBITEMHITTEST test */
958 static void test_lvm_subitemhittest_(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
959 BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
961 LVHITTESTINFO lpht;
962 INT ret;
964 lpht.pt.x = x;
965 lpht.pt.y = y;
967 ret = SendMessageA(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
969 todo_wine_if(todo_item)
971 ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
972 ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
975 todo_wine_if(todo_subitem)
976 ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
978 todo_wine_if(todo_flags)
979 ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
982 #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__)
984 static void test_images(void)
986 HWND hwnd;
987 INT r;
988 LVITEMA item;
989 HIMAGELIST himl;
990 HBITMAP hbmp;
991 RECT r1, r2;
992 static CHAR hello[] = "hello";
994 himl = pImageList_Create(40, 40, 0, 4, 4);
995 ok(himl != NULL, "failed to create imagelist\n");
997 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
998 ok(hbmp != NULL, "failed to create bitmap\n");
1000 r = pImageList_Add(himl, hbmp, 0);
1001 ok(r == 0, "should be zero\n");
1003 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_OWNERDRAWFIXED,
1004 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1005 ok(hwnd != NULL, "failed to create listview window\n");
1007 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
1008 LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
1010 ok(r == 0, "should return zero\n");
1012 r = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
1013 ok(r == 0, "should return zero\n");
1015 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
1016 ok(r != 0, "got 0\n");
1018 /* returns dimensions */
1020 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
1021 ok(r == 0, "should be zero items\n");
1023 item.mask = LVIF_IMAGE | LVIF_TEXT;
1024 item.iItem = 0;
1025 item.iSubItem = 1;
1026 item.iImage = 0;
1027 item.pszText = 0;
1028 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1029 ok(r == -1, "should fail\n");
1031 item.iSubItem = 0;
1032 item.pszText = hello;
1033 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1034 ok(r == 0, "should not fail\n");
1036 SetRect(&r1, LVIR_ICON, 0, 0, 0);
1037 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
1038 expect(1, r);
1040 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1041 ok(r == TRUE, "should not fail\n");
1043 item.iSubItem = 0;
1044 item.pszText = hello;
1045 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1046 ok(r == 0, "should not fail\n");
1048 SetRect(&r2, LVIR_ICON, 0, 0, 0);
1049 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
1050 expect(1, r);
1052 ok(EqualRect(&r1, &r2), "rectangle should be the same\n");
1054 DestroyWindow(hwnd);
1056 /* I_IMAGECALLBACK set for item, try to get image with invalid subitem. */
1057 hwnd = create_listview_control(LVS_REPORT);
1058 ok(hwnd != NULL, "Failed to create listview.\n");
1060 memset(&item, 0, sizeof(item));
1061 item.mask = LVIF_IMAGE;
1062 item.iImage = I_IMAGECALLBACK;
1063 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1064 ok(!r, "Failed to insert item.\n");
1066 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1068 memset(&item, 0, sizeof(item));
1069 item.mask = LVIF_IMAGE;
1070 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1071 ok(r, "Failed to get item.\n");
1073 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq, "get image dispinfo 1", FALSE);
1075 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1077 memset(&item, 0, sizeof(item));
1078 item.mask = LVIF_IMAGE;
1079 item.iSubItem = 1;
1080 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1081 ok(r, "Failed to get item.\n");
1083 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get image dispinfo 2", FALSE);
1085 DestroyWindow(hwnd);
1088 static void test_checkboxes(void)
1090 HWND hwnd;
1091 LVITEMA item;
1092 DWORD r;
1093 static CHAR text[] = "Text",
1094 text2[] = "Text2",
1095 text3[] = "Text3";
1097 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1098 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1099 ok(hwnd != NULL, "failed to create listview window\n");
1101 /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
1102 item.mask = LVIF_TEXT | LVIF_STATE;
1103 item.stateMask = 0xffff;
1104 item.state = 0xfccc;
1105 item.iItem = 0;
1106 item.iSubItem = 0;
1107 item.pszText = text;
1108 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1109 expect(0, r);
1111 item.iItem = 0;
1112 item.mask = LVIF_STATE;
1113 item.stateMask = 0xffff;
1114 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1115 expect(1, r);
1116 ok(item.state == 0xfccc, "state %x\n", item.state);
1118 /* Don't set LVIF_STATE */
1119 item.mask = LVIF_TEXT;
1120 item.stateMask = 0xffff;
1121 item.state = 0xfccc;
1122 item.iItem = 1;
1123 item.iSubItem = 0;
1124 item.pszText = text;
1125 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1126 expect(1, r);
1128 item.iItem = 1;
1129 item.mask = LVIF_STATE;
1130 item.stateMask = 0xffff;
1131 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1132 expect(1, r);
1133 ok(item.state == 0, "state %x\n", item.state);
1135 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1136 expect(0, r);
1138 /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
1139 item.iItem = 0;
1140 item.mask = LVIF_STATE;
1141 item.stateMask = 0xffff;
1142 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1143 expect(1, r);
1145 /* Now add an item without specifying a state and check that its state goes to 0x1000 */
1146 item.iItem = 2;
1147 item.mask = LVIF_TEXT;
1148 item.state = 0;
1149 item.pszText = text2;
1150 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1151 expect(2, r);
1153 item.iItem = 2;
1154 item.mask = LVIF_STATE;
1155 item.stateMask = 0xffff;
1156 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1157 expect(1, r);
1158 ok(item.state == 0x1000, "state %x\n", item.state);
1160 /* Add a further item this time specifying a state and still its state goes to 0x1000 */
1161 item.iItem = 3;
1162 item.mask = LVIF_TEXT | LVIF_STATE;
1163 item.stateMask = 0xffff;
1164 item.state = 0x2aaa;
1165 item.pszText = text3;
1166 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1167 expect(3, r);
1169 item.iItem = 3;
1170 item.mask = LVIF_STATE;
1171 item.stateMask = 0xffff;
1172 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1173 expect(1, r);
1174 ok(item.state == 0x1aaa, "state %x\n", item.state);
1176 /* Set an item's state to checked */
1177 item.iItem = 3;
1178 item.mask = LVIF_STATE;
1179 item.stateMask = 0xf000;
1180 item.state = 0x2000;
1181 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1182 expect(1, r);
1184 item.iItem = 3;
1185 item.mask = LVIF_STATE;
1186 item.stateMask = 0xffff;
1187 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1188 expect(1, r);
1189 ok(item.state == 0x2aaa, "state %x\n", item.state);
1191 /* Check that only the bits we asked for are returned,
1192 * and that all the others are set to zero
1194 item.iItem = 3;
1195 item.mask = LVIF_STATE;
1196 item.stateMask = 0xf000;
1197 item.state = 0xffff;
1198 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1199 expect(1, r);
1200 ok(item.state == 0x2000, "state %x\n", item.state);
1202 /* Set the style again and check that doesn't change an item's state */
1203 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1204 ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
1206 item.iItem = 3;
1207 item.mask = LVIF_STATE;
1208 item.stateMask = 0xffff;
1209 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1210 expect(1, r);
1211 ok(item.state == 0x2aaa, "state %x\n", item.state);
1213 /* Unsetting the checkbox extended style doesn't change an item's state */
1214 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
1215 ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
1217 item.iItem = 3;
1218 item.mask = LVIF_STATE;
1219 item.stateMask = 0xffff;
1220 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1221 expect(1, r);
1222 ok(item.state == 0x2aaa, "state %x\n", item.state);
1224 /* Now setting the style again will change an item's state */
1225 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
1226 expect(0, r);
1228 item.iItem = 3;
1229 item.mask = LVIF_STATE;
1230 item.stateMask = 0xffff;
1231 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1232 expect(1, r);
1233 ok(item.state == 0x1aaa, "state %x\n", item.state);
1235 /* Toggle checkbox tests (bug 9934) */
1236 memset (&item, 0xcc, sizeof(item));
1237 item.mask = LVIF_STATE;
1238 item.iItem = 3;
1239 item.iSubItem = 0;
1240 item.state = LVIS_FOCUSED;
1241 item.stateMask = LVIS_FOCUSED;
1242 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1243 expect(1, r);
1245 item.iItem = 3;
1246 item.mask = LVIF_STATE;
1247 item.stateMask = 0xffff;
1248 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1249 expect(1, r);
1250 ok(item.state == 0x1aab, "state %x\n", item.state);
1252 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1253 expect(0, r);
1254 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1255 expect(0, r);
1257 item.iItem = 3;
1258 item.mask = LVIF_STATE;
1259 item.stateMask = 0xffff;
1260 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1261 expect(1, r);
1262 ok(item.state == 0x2aab, "state %x\n", item.state);
1264 r = SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
1265 expect(0, r);
1266 r = SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
1267 expect(0, r);
1269 item.iItem = 3;
1270 item.mask = LVIF_STATE;
1271 item.stateMask = 0xffff;
1272 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1273 expect(1, r);
1274 ok(item.state == 0x1aab, "state %x\n", item.state);
1276 DestroyWindow(hwnd);
1279 static void insert_column(HWND hwnd, int idx)
1281 LVCOLUMNA column;
1282 INT rc;
1284 memset(&column, 0xcc, sizeof(column));
1285 column.mask = LVCF_SUBITEM;
1286 column.iSubItem = idx;
1288 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, idx, (LPARAM)&column);
1289 expect(idx, rc);
1292 static void insert_item(HWND hwnd, int idx)
1294 static CHAR text[] = "foo";
1296 LVITEMA item;
1297 INT rc;
1299 memset(&item, 0xcc, sizeof (item));
1300 item.mask = LVIF_TEXT;
1301 item.iItem = idx;
1302 item.iSubItem = 0;
1303 item.pszText = text;
1305 rc = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
1306 expect(idx, rc);
1309 static void test_items(void)
1311 const LPARAM lparamTest = 0x42;
1312 static CHAR text[] = "Text";
1313 char buffA[5];
1314 HWND hwnd;
1315 LVITEMA item;
1316 DWORD r;
1318 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1319 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1320 ok(hwnd != NULL, "failed to create listview window\n");
1323 * Test setting/getting item params
1326 /* Set up two columns */
1327 insert_column(hwnd, 0);
1328 insert_column(hwnd, 1);
1330 /* LVIS_SELECTED with zero stateMask */
1331 /* set */
1332 memset (&item, 0, sizeof (item));
1333 item.mask = LVIF_STATE;
1334 item.state = LVIS_SELECTED;
1335 item.stateMask = 0;
1336 item.iItem = 0;
1337 item.iSubItem = 0;
1338 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1339 expect(0, r);
1340 /* get */
1341 memset (&item, 0xcc, sizeof (item));
1342 item.mask = LVIF_STATE;
1343 item.stateMask = LVIS_SELECTED;
1344 item.state = 0;
1345 item.iItem = 0;
1346 item.iSubItem = 0;
1347 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1348 expect(1, r);
1349 ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1350 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1351 ok(r, "got %ld\n", r);
1353 /* LVIS_SELECTED with zero stateMask */
1354 /* set */
1355 memset (&item, 0, sizeof (item));
1356 item.mask = LVIF_STATE;
1357 item.state = LVIS_FOCUSED;
1358 item.stateMask = 0;
1359 item.iItem = 0;
1360 item.iSubItem = 0;
1361 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1362 expect(0, r);
1363 /* get */
1364 memset (&item, 0xcc, sizeof (item));
1365 item.mask = LVIF_STATE;
1366 item.stateMask = LVIS_FOCUSED;
1367 item.state = 0;
1368 item.iItem = 0;
1369 item.iSubItem = 0;
1370 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1371 expect(1, r);
1372 ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1373 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1374 ok(r, "got %ld\n", r);
1376 /* LVIS_CUT with LVIS_FOCUSED stateMask */
1377 /* set */
1378 memset (&item, 0, sizeof (item));
1379 item.mask = LVIF_STATE;
1380 item.state = LVIS_CUT;
1381 item.stateMask = LVIS_FOCUSED;
1382 item.iItem = 0;
1383 item.iSubItem = 0;
1384 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1385 expect(0, r);
1386 /* get */
1387 memset (&item, 0xcc, sizeof (item));
1388 item.mask = LVIF_STATE;
1389 item.stateMask = LVIS_CUT;
1390 item.state = 0;
1391 item.iItem = 0;
1392 item.iSubItem = 0;
1393 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1394 expect(1, r);
1395 ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1396 r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1397 ok(r, "got %ld\n", r);
1399 /* Insert an item with just a param */
1400 memset (&item, 0xcc, sizeof (item));
1401 item.mask = LVIF_PARAM;
1402 item.iItem = 0;
1403 item.iSubItem = 0;
1404 item.lParam = lparamTest;
1405 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1406 expect(0, r);
1408 /* Test getting of the param */
1409 memset (&item, 0xcc, sizeof (item));
1410 item.mask = LVIF_PARAM;
1411 item.iItem = 0;
1412 item.iSubItem = 0;
1413 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1414 expect(1, r);
1415 ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1417 /* Set up a subitem */
1418 memset (&item, 0xcc, sizeof (item));
1419 item.mask = LVIF_TEXT;
1420 item.iItem = 0;
1421 item.iSubItem = 1;
1422 item.pszText = text;
1423 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1424 expect(1, r);
1426 item.mask = LVIF_TEXT;
1427 item.iItem = 0;
1428 item.iSubItem = 1;
1429 item.pszText = buffA;
1430 item.cchTextMax = sizeof(buffA);
1431 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1432 expect(1, r);
1433 ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1435 /* set up with extra flag */
1436 /* 1. reset subitem text */
1437 item.mask = LVIF_TEXT;
1438 item.iItem = 0;
1439 item.iSubItem = 1;
1440 item.pszText = NULL;
1441 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1442 expect(1, r);
1444 item.mask = LVIF_TEXT;
1445 item.iItem = 0;
1446 item.iSubItem = 1;
1447 item.pszText = buffA;
1448 buffA[0] = 'a';
1449 item.cchTextMax = sizeof(buffA);
1450 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1451 expect(1, r);
1452 ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1454 /* 2. set new text with extra flag specified */
1455 item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1456 item.iItem = 0;
1457 item.iSubItem = 1;
1458 item.pszText = text;
1459 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1460 ok(r == 1 || broken(r == 0) /* NT4 */, "ret %ld\n", r);
1462 if (r == 1)
1464 item.mask = LVIF_TEXT;
1465 item.iItem = 0;
1466 item.iSubItem = 1;
1467 item.pszText = buffA;
1468 buffA[0] = 'a';
1469 item.cchTextMax = sizeof(buffA);
1470 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1471 expect(1, r);
1472 ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1475 /* Query param from subitem: returns main item param */
1476 memset (&item, 0xcc, sizeof (item));
1477 item.mask = LVIF_PARAM;
1478 item.iItem = 0;
1479 item.iSubItem = 1;
1480 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1481 expect(1, r);
1482 ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1484 /* Set up param on first subitem: no effect */
1485 memset (&item, 0xcc, sizeof (item));
1486 item.mask = LVIF_PARAM;
1487 item.iItem = 0;
1488 item.iSubItem = 1;
1489 item.lParam = lparamTest+1;
1490 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1491 expect(0, r);
1493 /* Query param from subitem again: should still return main item param */
1494 memset (&item, 0xcc, sizeof (item));
1495 item.mask = LVIF_PARAM;
1496 item.iItem = 0;
1497 item.iSubItem = 1;
1498 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1499 expect(1, r);
1500 ok(item.lParam == lparamTest, "got lParam %Ix, expected %Ix\n", item.lParam, lparamTest);
1502 /**** Some tests of state highlighting ****/
1503 memset (&item, 0xcc, sizeof (item));
1504 item.mask = LVIF_STATE;
1505 item.iItem = 0;
1506 item.iSubItem = 0;
1507 item.state = LVIS_SELECTED;
1508 item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1509 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1510 expect(1, r);
1511 item.iSubItem = 1;
1512 item.state = LVIS_DROPHILITED;
1513 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
1514 expect(1, r);
1516 memset (&item, 0xcc, sizeof (item));
1517 item.mask = LVIF_STATE;
1518 item.iItem = 0;
1519 item.iSubItem = 0;
1520 item.stateMask = -1;
1521 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1522 expect(1, r);
1523 ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1524 item.iSubItem = 1;
1525 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1526 expect(1, r);
1527 todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1529 /* some notnull but meaningless masks */
1530 memset (&item, 0, sizeof(item));
1531 item.mask = LVIF_NORECOMPUTE;
1532 item.iItem = 0;
1533 item.iSubItem = 0;
1534 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1535 expect(1, r);
1536 memset (&item, 0, sizeof(item));
1537 item.mask = LVIF_DI_SETITEM;
1538 item.iItem = 0;
1539 item.iSubItem = 0;
1540 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
1541 expect(1, r);
1543 /* set text to callback value already having it */
1544 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
1545 expect(TRUE, r);
1546 memset (&item, 0, sizeof (item));
1547 item.mask = LVIF_TEXT;
1548 item.pszText = LPSTR_TEXTCALLBACKA;
1549 item.iItem = 0;
1550 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
1551 expect(0, r);
1552 memset (&item, 0, sizeof (item));
1554 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1556 item.pszText = LPSTR_TEXTCALLBACKA;
1557 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0 , (LPARAM) &item);
1558 expect(TRUE, r);
1560 ok_sequence(sequences, PARENT_SEQ_INDEX, textcallback_set_again_parent_seq,
1561 "check callback text comparison rule", FALSE);
1563 DestroyWindow(hwnd);
1566 static void test_columns(void)
1568 HWND hwnd, header;
1569 LVCOLUMNA column;
1570 LVITEMA item;
1571 INT order[2];
1572 CHAR buff[5];
1573 DWORD rc;
1575 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_LIST,
1576 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1577 ok(hwnd != NULL, "failed to create listview window\n");
1579 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1580 ok(header == NULL, "got %p\n", header);
1582 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1583 ok(rc == 0, "got %ld\n", rc);
1585 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1586 ok(header == NULL, "got %p\n", header);
1588 DestroyWindow(hwnd);
1590 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", LVS_REPORT,
1591 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1592 ok(hwnd != NULL, "failed to create listview window\n");
1594 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, -1, 0);
1595 ok(!rc, "got %ld\n", rc);
1597 rc = SendMessageA(hwnd, LVM_DELETECOLUMN, 0, 0);
1598 ok(!rc, "got %ld\n", rc);
1600 /* Add a column with no mask */
1601 memset(&column, 0xcc, sizeof(column));
1602 column.mask = 0;
1603 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1604 ok(rc == 0, "Inserting column with no mask failed with %ld\n", rc);
1606 /* Check its width */
1607 rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1608 ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %ld\n", rc);
1610 DestroyWindow(hwnd);
1612 /* LVM_GETCOLUMNORDERARRAY */
1613 hwnd = create_listview_control(LVS_REPORT);
1614 subclass_header(hwnd);
1616 memset(&column, 0, sizeof(column));
1617 column.mask = LVCF_WIDTH;
1618 column.cx = 100;
1619 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&column);
1620 expect(0, rc);
1622 column.cx = 200;
1623 rc = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&column);
1624 expect(1, rc);
1626 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1628 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1629 expect(1, rc);
1630 ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1631 ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1633 rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0);
1634 expect(0, rc);
1636 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE);
1638 /* LVM_SETCOLUMNORDERARRAY */
1639 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1641 order[0] = 0;
1642 order[1] = 1;
1643 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
1644 expect(1, rc);
1646 rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0);
1647 expect(0, rc);
1649 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE);
1651 /* after column added subitem is considered as present */
1652 insert_item(hwnd, 0);
1654 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1656 item.pszText = buff;
1657 item.cchTextMax = sizeof(buff);
1658 item.iItem = 0;
1659 item.iSubItem = 1;
1660 item.mask = LVIF_TEXT;
1661 memset(&g_itema, 0, sizeof(g_itema));
1662 rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1663 expect(1, rc);
1664 ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1666 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
1667 "get subitem text after column added", FALSE);
1669 DestroyWindow(hwnd);
1671 /* Columns are not created right away. */
1672 hwnd = create_listview_control(LVS_REPORT);
1673 ok(hwnd != NULL, "Failed to create a listview window.\n");
1675 insert_item(hwnd, 0);
1677 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1678 ok(IsWindow(header), "Expected header handle.\n");
1679 rc = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
1680 ok(!rc, "Unexpected column count.\n");
1682 DestroyWindow(hwnd);
1685 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1686 static WNDPROC listviewWndProc;
1687 static HIMAGELIST test_create_imagelist;
1689 static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1691 LRESULT ret;
1693 if (uMsg == WM_CREATE)
1695 CREATESTRUCTA *lpcs = (CREATESTRUCTA*)lParam;
1696 lpcs->style |= LVS_REPORT;
1698 ret = CallWindowProcA(listviewWndProc, hwnd, uMsg, wParam, lParam);
1699 if (uMsg == WM_CREATE) SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist);
1700 return ret;
1703 /* Header creation is delayed in classic implementation. */
1704 #define TEST_NO_HEADER(a) test_header_presence_(a, FALSE, __LINE__)
1705 #define TEST_HEADER_EXPECTED(a) test_header_presence_(a, TRUE, __LINE__)
1706 #define TEST_NO_HEADER2(a, b) test_header_presence_(a, b, __LINE__)
1707 static void test_header_presence_(HWND hwnd, BOOL present, int line)
1709 HWND header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
1711 if (present)
1713 ok_(__FILE__, line)(IsWindow(header), "Header should have been created.\n");
1714 if (header) /* FIXME: remove when todo's are fixed */
1715 ok_(__FILE__, line)(header == GetDlgItem(hwnd, 0), "Dialog item expected.\n");
1717 else
1719 ok_(__FILE__, line)(!IsWindow(header), "Header shouldn't be created.\n");
1720 ok_(__FILE__, line)(NULL == GetDlgItem(hwnd, 0), "NULL dialog item expected.\n");
1724 static void test_create(BOOL is_version_6)
1726 char buff[16];
1727 HWND hList;
1728 HWND hHeader;
1729 LONG_PTR ret;
1730 LONG r;
1731 LVCOLUMNA col;
1732 RECT rect;
1733 WNDCLASSEXA cls;
1734 DWORD style;
1735 ATOM class;
1737 cls.cbSize = sizeof(WNDCLASSEXA);
1738 r = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
1739 ok(r, "Failed to get class info.\n");
1740 listviewWndProc = cls.lpfnWndProc;
1741 cls.lpfnWndProc = create_test_wndproc;
1742 cls.lpszClassName = "MyListView32";
1743 class = RegisterClassExA(&cls);
1744 ok(class, "Failed to register class.\n");
1746 test_create_imagelist = pImageList_Create(16, 16, 0, 5, 10);
1747 hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1748 ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1749 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1750 ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1751 ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1752 DestroyWindow(hList);
1754 /* header isn't created on LVS_ICON and LVS_LIST styles */
1755 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1756 TEST_NO_HEADER(hList);
1758 /* insert column */
1759 memset(&col, 0, sizeof(LVCOLUMNA));
1760 col.mask = LVCF_WIDTH;
1761 col.cx = 100;
1762 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1763 expect(0, r);
1764 TEST_HEADER_EXPECTED(hList);
1765 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1766 style = GetWindowLongA(hHeader, GWL_STYLE);
1767 ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1768 DestroyWindow(hList);
1770 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1771 GetModuleHandleA(NULL), 0);
1772 TEST_NO_HEADER(hList);
1773 /* insert column */
1774 memset(&col, 0, sizeof(LVCOLUMNA));
1775 col.mask = LVCF_WIDTH;
1776 col.cx = 100;
1777 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1778 expect(0, r);
1779 TEST_HEADER_EXPECTED(hList);
1780 DestroyWindow(hList);
1782 /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1783 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1784 GetModuleHandleA(NULL), 0);
1785 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongPtrA(hList, GWL_STYLE) | LVS_REPORT);
1786 ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1787 TEST_HEADER_EXPECTED(hList);
1788 ret = SetWindowLongPtrA(hList, GWL_STYLE, GetWindowLongA(hList, GWL_STYLE) & ~LVS_REPORT);
1789 ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1790 TEST_HEADER_EXPECTED(hList);
1791 DestroyWindow(hList);
1793 /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1794 hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1795 GetModuleHandleA(NULL), 0);
1796 ret = SetWindowLongPtrA(hList, GWL_STYLE,
1797 (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT);
1798 ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1799 TEST_HEADER_EXPECTED(hList);
1800 ret = SetWindowLongPtrA(hList, GWL_STYLE, (GetWindowLongPtrA(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST);
1801 ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1802 TEST_HEADER_EXPECTED(hList);
1803 DestroyWindow(hList);
1805 /* LVS_REPORT without WS_VISIBLE */
1806 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1807 GetModuleHandleA(NULL), 0);
1808 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1809 todo_wine_if(is_version_6)
1810 TEST_NO_HEADER2(hList, is_version_6);
1812 /* insert column */
1813 memset(&col, 0, sizeof(LVCOLUMNA));
1814 col.mask = LVCF_WIDTH;
1815 col.cx = 100;
1816 r = SendMessageA(hList, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
1817 expect(0, r);
1818 TEST_HEADER_EXPECTED(hList);
1819 DestroyWindow(hList);
1821 /* LVS_REPORT without WS_VISIBLE, try to show it */
1822 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1823 GetModuleHandleA(NULL), 0);
1824 todo_wine_if(is_version_6)
1825 TEST_NO_HEADER2(hList, is_version_6);
1827 ShowWindow(hList, SW_SHOW);
1828 TEST_HEADER_EXPECTED(hList);
1829 DestroyWindow(hList);
1831 /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1832 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE,
1833 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1834 TEST_HEADER_EXPECTED(hList);
1835 hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1836 /* HDS_DRAGDROP set by default */
1837 ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1838 DestroyWindow(hList);
1840 /* setting LVS_EX_HEADERDRAGDROP creates header */
1841 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1842 GetModuleHandleA(NULL), 0);
1843 todo_wine_if(is_version_6)
1844 TEST_NO_HEADER2(hList, is_version_6);
1846 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1847 TEST_HEADER_EXPECTED(hList);
1848 DestroyWindow(hList);
1850 /* setting LVS_EX_GRIDLINES creates header */
1851 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1852 GetModuleHandleA(NULL), 0);
1853 todo_wine_if(is_version_6)
1854 TEST_NO_HEADER2(hList, is_version_6);
1856 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);
1857 TEST_HEADER_EXPECTED(hList);
1858 DestroyWindow(hList);
1860 /* setting LVS_EX_FULLROWSELECT creates header */
1861 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1862 GetModuleHandleA(NULL), 0);
1863 todo_wine_if(is_version_6)
1864 TEST_NO_HEADER2(hList, is_version_6);
1865 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
1866 TEST_HEADER_EXPECTED(hList);
1867 DestroyWindow(hList);
1869 /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1870 hList = create_listview_control(LVS_ICON);
1871 SendMessageA(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP);
1872 r = SendMessageA(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1873 ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1874 DestroyWindow(hList);
1876 /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1877 hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1878 GetModuleHandleA(NULL), 0);
1879 todo_wine_if(is_version_6)
1880 TEST_NO_HEADER2(hList, is_version_6);
1882 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1883 r = SendMessageA(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
1884 ok(r == 1, "Unexpected ret value %ld.\n", r);
1885 /* right value contains garbage, probably because header columns are not set up */
1886 ok(rect.bottom >= 0, "Unexpected rectangle.\n");
1888 todo_wine_if(is_version_6)
1889 TEST_NO_HEADER2(hList, is_version_6);
1890 DestroyWindow(hList);
1892 /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1893 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1894 hList = CreateWindowExA(0, WC_LISTVIEWA, NULL,
1895 WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_OWNERDRAWFIXED | LVS_REPORT,
1896 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1897 ok(hList != NULL, "Failed to create ListView window.\n");
1898 ok_sequence(sequences, PARENT_SEQ_INDEX, create_ownerdrawfixed_parent_seq,
1899 "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1900 DestroyWindow(hList);
1902 /* Test that window text is preserved. */
1903 hList = CreateWindowExA(0, WC_LISTVIEWA, "test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1904 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1905 ok(hList != NULL, "Failed to create ListView window.\n");
1906 *buff = 0;
1907 GetWindowTextA(hList, buff, sizeof(buff));
1908 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1909 DestroyWindow(hList);
1911 hList = CreateWindowExW(0, WC_LISTVIEWW, L"test text", WS_CHILD | WS_BORDER | WS_VISIBLE,
1912 0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1913 ok(hList != NULL, "Failed to create ListView window.\n");
1914 *buff = 0;
1915 GetWindowTextA(hList, buff, sizeof(buff));
1916 ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1917 DestroyWindow(hList);
1919 r = UnregisterClassA("MyListView32", NULL);
1920 ok(r, "Failed to unregister test class.\n");
1923 static void test_redraw(void)
1925 HWND hwnd;
1926 HDC hdc;
1927 BOOL res;
1928 DWORD r;
1929 RECT rect;
1931 hwnd = create_listview_control(LVS_REPORT);
1932 subclass_header(hwnd);
1934 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1936 InvalidateRect(hwnd, NULL, TRUE);
1937 UpdateWindow(hwnd);
1938 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, redraw_listview_seq, "redraw listview", FALSE);
1940 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1942 /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1943 /* 1. Without backbuffer */
1944 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1945 expect(TRUE, res);
1947 hdc = GetWindowDC(hwndparent);
1949 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1950 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1951 ok(r == 1, "Expected not zero result\n");
1952 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1953 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1955 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1956 expect(TRUE, res);
1958 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1959 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1960 expect(1, r);
1961 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1962 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1964 /* 2. With backbuffer */
1965 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER,
1966 LVS_EX_DOUBLEBUFFER);
1967 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
1968 expect(TRUE, res);
1970 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1971 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1972 expect(1, r);
1973 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq,
1974 "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1976 res = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_DEFAULT);
1977 expect(TRUE, res);
1979 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1980 r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
1981 todo_wine expect(1, r);
1982 ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq,
1983 "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1985 ReleaseDC(hwndparent, hdc);
1987 /* test setting the window style to what it already was */
1988 UpdateWindow(hwnd);
1989 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE));
1990 GetUpdateRect(hwnd, &rect, FALSE);
1991 ok(rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0,
1992 "Expected empty update rect, got %s\n", wine_dbgstr_rect(&rect));
1994 DestroyWindow(hwnd);
1997 static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1999 COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
2001 if(message == WM_NOTIFY) {
2002 NMHDR *nmhdr = (NMHDR*)lParam;
2003 if(nmhdr->code == NM_CUSTOMDRAW) {
2004 NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
2005 BOOL showsel_always = !!(GetWindowLongA(nmlvcd->nmcd.hdr.hwndFrom, GWL_STYLE) & LVS_SHOWSELALWAYS);
2006 BOOL is_selected = !!(nmlvcd->nmcd.uItemState & CDIS_SELECTED);
2007 struct message msg;
2009 msg.message = message;
2010 msg.flags = sent|wparam|lparam|custdraw;
2011 msg.wParam = wParam;
2012 msg.lParam = lParam;
2013 msg.id = nmhdr->code;
2014 msg.stage = nmlvcd->nmcd.dwDrawStage;
2015 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
2017 switch(nmlvcd->nmcd.dwDrawStage) {
2018 case CDDS_PREPAINT:
2019 SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
2020 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
2021 case CDDS_ITEMPREPAINT:
2022 clr = GetBkColor(nmlvcd->nmcd.hdc);
2023 todo_wine_if(nmlvcd->iSubItem)
2024 ok(clr == c0ffee, "Unexpected background color %#lx.\n", clr);
2025 nmlvcd->clrTextBk = CLR_DEFAULT;
2026 nmlvcd->clrText = RGB(0, 255, 0);
2027 return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT;
2028 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
2029 clr = GetBkColor(nmlvcd->nmcd.hdc);
2030 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "Unexpected text background %#lx.\n", nmlvcd->clrTextBk);
2031 ok(nmlvcd->clrText == RGB(0, 255, 0), "Unexpected text color %#lx.\n", nmlvcd->clrText);
2032 if (showsel_always && is_selected && nmlvcd->iSubItem)
2033 ok(clr == GetSysColor(COLOR_3DFACE), "Unexpected background color %#lx.\n", clr);
2034 else
2035 todo_wine_if(nmlvcd->iSubItem)
2036 ok(clr == c0ffee, "clr=%.8lx\n", clr);
2037 return CDRF_NOTIFYPOSTPAINT;
2038 case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
2039 clr = GetBkColor(nmlvcd->nmcd.hdc);
2040 if (showsel_always && is_selected)
2041 ok(clr == GetSysColor(COLOR_3DFACE), "Unexpected background color %#lx.\n", clr);
2042 else
2044 todo_wine
2045 ok(clr == c0ffee, "Unexpected background color %#lx.\n", clr);
2048 ok(nmlvcd->clrTextBk == CLR_DEFAULT, "Unexpected text background color %#lx.\n", nmlvcd->clrTextBk);
2049 ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%lx\n", nmlvcd->clrText);
2050 return CDRF_DODEFAULT;
2052 return CDRF_DODEFAULT;
2056 return DefWindowProcA(hwnd, message, wParam, lParam);
2059 static void test_customdraw(void)
2061 HWND hwnd;
2062 WNDPROC oldwndproc;
2063 LVITEMA item;
2065 hwnd = create_listview_control(LVS_REPORT);
2067 insert_column(hwnd, 0);
2068 insert_column(hwnd, 1);
2069 insert_item(hwnd, 0);
2071 oldwndproc = (WNDPROC)SetWindowLongPtrA(hwndparent, GWLP_WNDPROC,
2072 (LONG_PTR)cd_wndproc);
2074 InvalidateRect(hwnd, NULL, TRUE);
2075 UpdateWindow(hwnd);
2077 /* message tests */
2078 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2079 InvalidateRect(hwnd, NULL, TRUE);
2080 UpdateWindow(hwnd);
2081 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
2083 /* Check colors when item is selected. */
2084 item.mask = LVIF_STATE;
2085 item.stateMask = LVIS_SELECTED;
2086 item.state = LVIS_SELECTED;
2087 SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2089 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2090 InvalidateRect(hwnd, NULL, TRUE);
2091 UpdateWindow(hwnd);
2092 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq,
2093 "parent customdraw, item selected, LVS_REPORT, selection", FALSE);
2095 SetWindowLongW(hwnd, GWL_STYLE, GetWindowLongW(hwnd, GWL_STYLE) | LVS_SHOWSELALWAYS);
2096 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2097 InvalidateRect(hwnd, NULL, TRUE);
2098 UpdateWindow(hwnd);
2099 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq,
2100 "parent customdraw, item selected, LVS_SHOWSELALWAYS, LVS_REPORT", FALSE);
2102 DestroyWindow(hwnd);
2104 hwnd = create_listview_control(LVS_LIST);
2106 insert_column(hwnd, 0);
2107 insert_column(hwnd, 1);
2108 insert_item(hwnd, 0);
2110 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2111 InvalidateRect(hwnd, NULL, TRUE);
2112 UpdateWindow(hwnd);
2113 ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
2115 SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc);
2116 DestroyWindow(hwnd);
2119 static void test_icon_spacing(void)
2121 /* LVM_SETICONSPACING */
2122 /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
2124 HWND hwnd;
2125 WORD w, h;
2126 INT r;
2128 hwnd = create_listview_control(LVS_ICON);
2129 ok(hwnd != NULL, "failed to create a listview window\n");
2131 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
2132 expect(NFR_ANSI, r);
2134 /* reset the icon spacing to defaults */
2135 SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
2137 /* now we can request what the defaults are */
2138 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1));
2139 w = LOWORD(r);
2140 h = HIWORD(r);
2142 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2144 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30));
2145 ok(r == MAKELONG(w, h) ||
2146 broken(r == MAKELONG(w, w)), /* win98 */
2147 "Expected %ld, got %d\n", MAKELONG(w, h), r);
2149 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35));
2150 expect(MAKELONG(20,30), r);
2152 r = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1));
2153 expect(MAKELONG(25,35), r);
2155 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE);
2157 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2158 DestroyWindow(hwnd);
2161 static void test_color(void)
2163 RECT rect;
2164 HWND hwnd;
2165 DWORD r;
2166 int i;
2168 COLORREF color;
2169 COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
2171 hwnd = create_listview_control(LVS_REPORT);
2172 ok(hwnd != NULL, "failed to create a listview window\n");
2174 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2176 for (i = 0; i < 4; i++)
2178 color = colors[i];
2180 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, color);
2181 expect(TRUE, r);
2182 r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
2183 expect(color, r);
2185 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, color);
2186 expect (TRUE, r);
2187 r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
2188 expect(color, r);
2190 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, color);
2191 expect(TRUE, r);
2192 r = SendMessageA(hwnd, LVM_GETTEXTBKCOLOR, 0, 0);
2193 expect(color, r);
2196 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_color_seq, "test color seq", FALSE);
2197 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2199 /* invalidation test done separately to avoid a message chain mess */
2200 r = ValidateRect(hwnd, NULL);
2201 expect(TRUE, r);
2202 r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
2203 expect(TRUE, r);
2205 rect.right = rect.bottom = 1;
2206 r = GetUpdateRect(hwnd, &rect, TRUE);
2207 expect(FALSE, r);
2208 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle %s\n", wine_dbgstr_rect(&rect));
2210 r = ValidateRect(hwnd, NULL);
2211 expect(TRUE, r);
2212 r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
2213 expect(TRUE, r);
2215 rect.right = rect.bottom = 1;
2216 r = GetUpdateRect(hwnd, &rect, TRUE);
2217 expect(FALSE, r);
2218 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle %s\n", wine_dbgstr_rect(&rect));
2220 r = ValidateRect(hwnd, NULL);
2221 expect(TRUE, r);
2222 r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2223 expect(TRUE, r);
2225 rect.right = rect.bottom = 1;
2226 r = GetUpdateRect(hwnd, &rect, TRUE);
2227 expect(FALSE, r);
2228 ok(rect.right == 0 && rect.bottom == 0, "got update rectangle %s\n", wine_dbgstr_rect(&rect));
2230 DestroyWindow(hwnd);
2233 static void test_item_count(void)
2235 /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2237 HWND hwnd;
2238 DWORD r;
2239 HDC hdc;
2240 HFONT hOldFont;
2241 TEXTMETRICA tm;
2242 RECT rect;
2243 INT height;
2245 LVITEMA item0;
2246 LVITEMA item1;
2247 LVITEMA item2;
2248 static CHAR item0text[] = "item0";
2249 static CHAR item1text[] = "item1";
2250 static CHAR item2text[] = "item2";
2252 hwnd = create_listview_control(LVS_REPORT);
2253 ok(hwnd != NULL, "failed to create a listview window\n");
2255 /* resize in dpiaware manner to fit all 3 items added */
2256 hdc = GetDC(0);
2257 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
2258 GetTextMetricsA(hdc, &tm);
2259 /* 2 extra pixels for bounds and header border */
2260 height = tm.tmHeight + 2;
2261 SelectObject(hdc, hOldFont);
2262 ReleaseDC(0, hdc);
2264 GetWindowRect(hwnd, &rect);
2265 /* 3 items + 1 header + 1 to be sure */
2266 MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2268 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2270 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2271 expect(0, r);
2273 /* [item0] */
2274 item0.mask = LVIF_TEXT;
2275 item0.iItem = 0;
2276 item0.iSubItem = 0;
2277 item0.pszText = item0text;
2278 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2279 expect(0, r);
2281 /* [item0, item1] */
2282 item1.mask = LVIF_TEXT;
2283 item1.iItem = 1;
2284 item1.iSubItem = 0;
2285 item1.pszText = item1text;
2286 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2287 expect(1, r);
2289 /* [item0, item1, item2] */
2290 item2.mask = LVIF_TEXT;
2291 item2.iItem = 2;
2292 item2.iSubItem = 0;
2293 item2.pszText = item2text;
2294 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2295 expect(2, r);
2297 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2298 expect(3, r);
2300 /* [item0, item1] */
2301 r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2302 expect(TRUE, r);
2304 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2305 expect(2, r);
2307 /* [] */
2308 r = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
2309 expect(TRUE, r);
2311 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2312 expect(0, r);
2314 /* [item0] */
2315 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2316 expect(0, r);
2318 /* [item0, item1] */
2319 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2320 expect(1, r);
2322 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2323 expect(2, r);
2325 /* [item0, item1, item2] */
2326 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2327 expect(2, r);
2329 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2330 expect(3, r);
2332 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_item_count_seq, "test item count seq", FALSE);
2334 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2335 DestroyWindow(hwnd);
2338 static void test_item_position(void)
2340 /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2342 HWND hwnd;
2343 DWORD r;
2344 POINT position;
2346 LVITEMA item0;
2347 LVITEMA item1;
2348 LVITEMA item2;
2349 static CHAR item0text[] = "item0";
2350 static CHAR item1text[] = "item1";
2351 static CHAR item2text[] = "item2";
2353 hwnd = create_listview_control(LVS_ICON);
2354 ok(hwnd != NULL, "failed to create a listview window\n");
2356 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2358 /* [item0] */
2359 item0.mask = LVIF_TEXT;
2360 item0.iItem = 0;
2361 item0.iSubItem = 0;
2362 item0.pszText = item0text;
2363 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2364 expect(0, r);
2366 /* [item0, item1] */
2367 item1.mask = LVIF_TEXT;
2368 item1.iItem = 1;
2369 item1.iSubItem = 0;
2370 item1.pszText = item1text;
2371 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item1);
2372 expect(1, r);
2374 /* [item0, item1, item2] */
2375 item2.mask = LVIF_TEXT;
2376 item2.iItem = 2;
2377 item2.iSubItem = 0;
2378 item2.pszText = item2text;
2379 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item2);
2380 expect(2, r);
2382 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 1, MAKELPARAM(10,5));
2383 expect(TRUE, r);
2384 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2385 expect(TRUE, r);
2386 expect2(10, 5, position.x, position.y);
2388 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 2, MAKELPARAM(0,0));
2389 expect(TRUE, r);
2390 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2391 expect(TRUE, r);
2392 expect2(0, 0, position.x, position.y);
2394 r = SendMessageA(hwnd, LVM_SETITEMPOSITION, 0, MAKELPARAM(20,20));
2395 expect(TRUE, r);
2396 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2397 expect(TRUE, r);
2398 expect2(20, 20, position.x, position.y);
2400 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2402 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2403 DestroyWindow(hwnd);
2406 static void test_getorigin(void)
2408 /* LVM_GETORIGIN */
2410 HWND hwnd;
2411 DWORD r;
2412 POINT position;
2414 position.x = position.y = 0;
2416 hwnd = create_listview_control(LVS_ICON);
2417 ok(hwnd != NULL, "failed to create a listview window\n");
2418 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2420 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2421 expect(TRUE, r);
2422 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2423 DestroyWindow(hwnd);
2425 hwnd = create_listview_control(LVS_SMALLICON);
2426 ok(hwnd != NULL, "failed to create a listview window\n");
2427 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2429 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2430 expect(TRUE, r);
2431 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2432 DestroyWindow(hwnd);
2434 hwnd = create_listview_control(LVS_LIST);
2435 ok(hwnd != NULL, "failed to create a listview window\n");
2436 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2438 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2439 expect(FALSE, r);
2440 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2441 DestroyWindow(hwnd);
2443 hwnd = create_listview_control(LVS_REPORT);
2444 ok(hwnd != NULL, "failed to create a listview window\n");
2445 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2447 r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2448 expect(FALSE, r);
2449 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2450 DestroyWindow(hwnd);
2453 static void test_multiselect(void)
2455 typedef struct t_select_task
2457 const char *descr;
2458 int initPos;
2459 int loopVK;
2460 int count;
2461 int result;
2462 } select_task;
2464 HWND hwnd;
2465 INT r;
2466 int i, j;
2467 static const int items=5;
2468 DWORD item_count;
2469 select_task task;
2470 LONG_PTR style;
2471 LVITEMA item;
2473 static struct t_select_task task_list[] = {
2474 { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2475 { "using VK_UP", -1, VK_UP, -1, -1 },
2476 { "using VK_END", 0, VK_END, 1, -1 },
2477 { "using VK_HOME", -1, VK_HOME, 1, -1 }
2480 hwnd = create_listview_control(LVS_REPORT);
2482 for (i = 0; i < items; i++)
2483 insert_item(hwnd, 0);
2485 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2486 expect(items, item_count);
2488 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2489 ok(r == -1, "got %d\n", r);
2491 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2492 ok(r == -1, "got %d\n", r);
2494 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
2495 ok(r == 0, "got %d\n", r);
2497 /* out of range index */
2498 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, items);
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 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -2);
2505 ok(r == 0, "got %d\n", r);
2507 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2508 ok(r == 0, "got %d\n", r);
2510 for (i = 0; i < ARRAY_SIZE(task_list); i++) {
2511 DWORD selected_count;
2512 LVITEMA item;
2514 task = task_list[i];
2516 /* deselect all items */
2517 item.state = 0;
2518 item.stateMask = LVIS_SELECTED;
2519 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2520 ok(r, "got %d\n", r);
2521 SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2523 /* set initial position */
2524 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2525 ok(r, "got %d\n", r);
2527 item.state = LVIS_SELECTED;
2528 item.stateMask = LVIS_SELECTED;
2529 r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2530 ok(r, "got %d\n", r);
2532 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2533 ok(selected_count == 1, "expected 1, got %ld\n", selected_count);
2535 hold_key(VK_SHIFT);
2537 for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2538 r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2539 expect(0,r);
2540 r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2541 expect(0,r);
2544 selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2546 ok((task.result == -1 ? item_count : task.result) == selected_count,
2547 "Failed multiple selection %s. There should be %ld selected items (is %ld)\n",
2548 task.descr, item_count, selected_count);
2550 release_key(VK_SHIFT);
2552 DestroyWindow(hwnd);
2554 /* make multiple selection, then switch to LVS_SINGLESEL */
2555 hwnd = create_listview_control(LVS_REPORT);
2556 for (i=0;i<items;i++) {
2557 insert_item(hwnd, 0);
2559 item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2560 expect(items,item_count);
2562 /* try with NULL pointer */
2563 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2564 expect(FALSE, r);
2566 /* select all, check notifications */
2567 item.state = 0;
2568 item.stateMask = LVIS_SELECTED;
2569 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2570 ok(r, "got %d\n", r);
2572 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2574 item.stateMask = LVIS_SELECTED;
2575 item.state = LVIS_SELECTED;
2576 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2577 expect(TRUE, r);
2579 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2580 "select all notification", FALSE);
2582 /* select all again (all selected already) */
2583 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2585 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2587 item.stateMask = LVIS_SELECTED;
2588 item.state = LVIS_SELECTED;
2589 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2590 expect(TRUE, r);
2592 ok(g_nmlistview_changing.uNewState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uNewState);
2593 ok(g_nmlistview_changing.uOldState == LVIS_SELECTED, "got 0x%x\n", g_nmlistview_changing.uOldState);
2594 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2596 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2597 "select all notification 2", FALSE);
2599 /* deselect all items */
2600 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2602 item.state = 0;
2603 item.stateMask = LVIS_SELECTED;
2604 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2605 ok(r, "got %d\n", r);
2607 ok_sequence(sequences, PARENT_SEQ_INDEX, change_all_parent_seq,
2608 "deselect all notification", FALSE);
2610 /* deselect all items again */
2611 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2612 item.state = 0;
2613 item.stateMask = LVIS_SELECTED;
2614 SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2615 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2617 /* any non-zero state value does the same */
2618 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2620 memset(&g_nmlistview_changing, 0xcc, sizeof(g_nmlistview_changing));
2622 item.stateMask = LVIS_SELECTED;
2623 item.state = LVIS_CUT;
2624 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2625 expect(TRUE, r);
2627 ok(g_nmlistview_changing.uNewState == 0, "got 0x%x\n", g_nmlistview_changing.uNewState);
2628 ok(g_nmlistview_changing.uOldState == 0, "got 0x%x\n", g_nmlistview_changing.uOldState);
2629 ok(g_nmlistview_changing.uChanged == LVIF_STATE, "got 0x%x\n", g_nmlistview_changing.uChanged);
2631 ok_sequence(sequences, PARENT_SEQ_INDEX, changing_all_parent_seq,
2632 "set state all notification 3", FALSE);
2634 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2635 ok(r, "got %d\n", r);
2636 for (i = 0; i < 3; i++) {
2637 item.state = LVIS_SELECTED;
2638 item.stateMask = LVIS_SELECTED;
2639 r = SendMessageA(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
2640 ok(r, "got %d\n", r);
2643 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2644 expect(3, r);
2645 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2646 expect(-1, r);
2648 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2649 ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2650 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SINGLESEL);
2651 /* check that style is accepted */
2652 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2653 ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2655 for (i=0;i<3;i++) {
2656 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2657 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2659 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2660 expect(3, r);
2661 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2662 ok(r == -1, "got %d\n", r);
2664 /* select one more */
2665 item.state = LVIS_SELECTED;
2666 item.stateMask = LVIS_SELECTED;
2667 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
2668 ok(r, "got %d\n", r);
2670 for (i=0;i<3;i++) {
2671 r = SendMessageA(hwnd, LVM_GETITEMSTATE, i, LVIS_SELECTED);
2672 ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2675 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 3, LVIS_SELECTED);
2676 ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2678 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2679 expect(1, r);
2680 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2681 expect(-1, r);
2683 /* try to select all on LVS_SINGLESEL */
2684 memset(&item, 0, sizeof(item));
2685 item.stateMask = LVIS_SELECTED;
2686 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2687 expect(TRUE, r);
2688 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2689 ok(r == -1, "got %d\n", r);
2691 item.stateMask = LVIS_SELECTED;
2692 item.state = LVIS_SELECTED;
2693 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2694 expect(FALSE, r);
2696 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2697 expect(0, r);
2698 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2699 expect(-1, r);
2701 /* try to deselect all on LVS_SINGLESEL */
2702 item.stateMask = LVIS_SELECTED;
2703 item.state = LVIS_SELECTED;
2704 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2705 expect(TRUE, r);
2707 item.stateMask = LVIS_SELECTED;
2708 item.state = 0;
2709 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2710 expect(TRUE, r);
2711 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2712 expect(0, r);
2714 /* 1. selection mark is update when new focused item is set */
2715 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2716 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2718 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2719 expect(-1, r);
2721 item.stateMask = LVIS_FOCUSED;
2722 item.state = LVIS_FOCUSED;
2723 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
2724 expect(TRUE, r);
2726 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2727 expect(0, r);
2729 /* it's not updated if already set */
2730 item.stateMask = LVIS_FOCUSED;
2731 item.state = LVIS_FOCUSED;
2732 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2733 expect(TRUE, r);
2735 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2736 expect(0, r);
2738 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2739 expect(0, r);
2741 item.stateMask = LVIS_FOCUSED;
2742 item.state = LVIS_FOCUSED;
2743 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 1, (LPARAM)&item);
2744 expect(TRUE, r);
2746 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2747 expect(-1, r);
2749 /* need to reset focused item first */
2750 item.stateMask = LVIS_FOCUSED;
2751 item.state = 0;
2752 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2753 expect(TRUE, r);
2755 item.stateMask = LVIS_FOCUSED;
2756 item.state = LVIS_FOCUSED;
2757 r = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
2758 expect(TRUE, r);
2760 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2761 expect(2, r);
2763 item.stateMask = LVIS_FOCUSED;
2764 item.state = 0;
2765 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2766 expect(TRUE, r);
2768 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2769 expect(2, r);
2771 /* 2. same tests, with LVM_SETITEM */
2772 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
2773 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SINGLESEL);
2775 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2776 expect(2, r);
2778 item.stateMask = LVIS_FOCUSED;
2779 item.state = LVIS_FOCUSED;
2780 item.mask = LVIF_STATE;
2781 item.iItem = item.iSubItem = 0;
2782 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2783 expect(TRUE, r);
2785 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2786 expect(0, r);
2788 /* it's not updated if already set */
2789 item.stateMask = LVIS_FOCUSED;
2790 item.state = LVIS_FOCUSED;
2791 item.mask = LVIF_STATE;
2792 item.iItem = 1;
2793 item.iSubItem = 0;
2794 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2795 expect(TRUE, r);
2797 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2798 expect(0, r);
2800 r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, -1);
2801 expect(0, r);
2803 item.stateMask = LVIS_FOCUSED;
2804 item.state = LVIS_FOCUSED;
2805 item.mask = LVIF_STATE;
2806 item.iItem = 1;
2807 item.iSubItem = 0;
2808 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2809 expect(TRUE, r);
2811 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2812 expect(-1, r);
2814 /* need to reset focused item first */
2815 item.stateMask = LVIS_FOCUSED;
2816 item.state = 0;
2817 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2818 expect(TRUE, r);
2820 item.stateMask = LVIS_FOCUSED;
2821 item.state = LVIS_FOCUSED;
2822 item.mask = LVIF_STATE;
2823 item.iItem = 2;
2824 item.iSubItem = 0;
2825 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
2826 expect(TRUE, r);
2828 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2829 expect(2, r);
2831 item.stateMask = LVIS_FOCUSED;
2832 item.state = 0;
2833 r = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
2834 expect(TRUE, r);
2836 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
2837 expect(2, r);
2839 DestroyWindow(hwnd);
2842 static void test_subitem_rect(void)
2844 HWND hwnd;
2845 DWORD r;
2846 LVCOLUMNA col;
2847 RECT rect, rect2;
2848 INT arr[3];
2850 /* test LVM_GETSUBITEMRECT for header */
2851 hwnd = create_listview_control(LVS_REPORT);
2852 ok(hwnd != NULL, "failed to create a listview window\n");
2853 /* add some columns */
2854 memset(&col, 0, sizeof(LVCOLUMNA));
2855 col.mask = LVCF_WIDTH;
2856 col.cx = 100;
2857 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2858 expect(0, r);
2859 col.cx = 150;
2860 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2861 expect(1, r);
2862 col.cx = 200;
2863 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2864 expect(2, r);
2865 /* item = -1 means header, subitem index is 1 based */
2866 SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2867 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2868 expect(0, r);
2870 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2871 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2872 expect(1, r);
2874 expect(100, rect.left);
2875 expect(250, rect.right);
2876 expect(3, rect.top);
2878 SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2879 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2880 expect(1, r);
2882 expect(250, rect.left);
2883 expect(450, rect.right);
2884 expect(3, rect.top);
2886 /* item LVS_REPORT padding isn't applied to subitems */
2887 insert_item(hwnd, 0);
2889 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2890 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2891 expect(1, r);
2892 expect(100, rect.left);
2893 expect(250, rect.right);
2895 SetRect(&rect, LVIR_ICON, 1, 0, 0);
2896 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2897 expect(1, r);
2898 /* no icon attached - zero width rectangle, with no left padding */
2899 expect(100, rect.left);
2900 expect(100, rect.right);
2902 SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2903 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2904 expect(1, r);
2905 /* same as full LVIR_BOUNDS */
2906 expect(100, rect.left);
2907 expect(250, rect.right);
2909 r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2910 ok(r, "got %ld\n", r);
2912 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2913 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2914 expect(1, r);
2915 expect(90, rect.left);
2916 expect(240, rect.right);
2918 SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2920 /* test header interaction */
2921 subclass_header(hwnd);
2922 flush_sequences(sequences, NUM_MSG_SEQUENCES);
2924 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2925 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
2926 expect(1, r);
2928 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2929 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2930 expect(1, r);
2932 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2933 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -10, (LPARAM)&rect);
2934 expect(1, r);
2936 SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2937 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 20, (LPARAM)&rect);
2938 expect(1, r);
2940 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2942 DestroyWindow(hwnd);
2944 /* test subitem rects after re-arranging columns */
2945 hwnd = create_listview_control(LVS_REPORT);
2946 ok(hwnd != NULL, "failed to create a listview window\n");
2947 memset(&col, 0, sizeof(LVCOLUMNA));
2948 col.mask = LVCF_WIDTH;
2950 col.cx = 100;
2951 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2952 expect(0, r);
2954 col.cx = 200;
2955 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2956 expect(1, r);
2958 col.cx = 300;
2959 r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2960 expect(2, r);
2962 insert_item(hwnd, 0);
2963 insert_item(hwnd, 1);
2965 /* wrong item is refused for main item */
2966 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2967 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect);
2968 expect(FALSE, r);
2970 /* for subitems rectangle is calculated even if there's no item added */
2971 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2972 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect);
2973 expect(TRUE, r);
2975 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2976 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 2, (LPARAM)&rect2);
2977 expect(TRUE, r);
2978 expect(rect.right, rect2.right);
2979 expect(rect.left, rect2.left);
2980 expect(rect.bottom, rect2.top);
2981 ok(rect2.bottom > rect2.top, "expected not zero height\n");
2983 arr[0] = 1; arr[1] = 0; arr[2] = 2;
2984 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 3, (LPARAM)arr);
2985 expect(TRUE, r);
2987 SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2988 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2989 expect(TRUE, r);
2990 expect(0, rect.left);
2991 expect(600, rect.right);
2993 SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2994 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
2995 expect(TRUE, r);
2996 expect(0, rect.left);
2997 expect(200, rect.right);
2999 SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
3000 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 1, (LPARAM)&rect2);
3001 expect(TRUE, r);
3002 expect(0, rect2.left);
3003 expect(200, rect2.right);
3004 /* items are of the same height */
3005 ok(rect2.top > 0, "expected positive item height\n");
3006 expect(rect.bottom, rect2.top);
3007 expect(rect.bottom * 2 - rect.top, rect2.bottom);
3009 SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
3010 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, 0, (LPARAM)&rect);
3011 expect(TRUE, r);
3012 expect(300, rect.left);
3013 expect(600, rect.right);
3015 DestroyWindow(hwnd);
3017 /* try it for non LVS_REPORT style */
3018 hwnd = CreateWindowA(WC_LISTVIEWA, "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
3019 GetModuleHandleA(NULL), 0);
3020 SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
3021 r = SendMessageA(hwnd, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect);
3022 expect(0, r);
3023 /* rect is unchanged */
3024 expect(0, rect.left);
3025 expect(-10, rect.right);
3026 expect(1, rect.top);
3027 expect(-10, rect.bottom);
3028 DestroyWindow(hwnd);
3031 /* comparison callback for test_sorting */
3032 static INT WINAPI test_CallBackCompare(LPARAM first, LPARAM second, LPARAM lParam)
3034 if (first == second) return 0;
3035 return (first > second ? 1 : -1);
3038 static void test_sorting(void)
3040 HWND hwnd;
3041 LVITEMA item = {0};
3042 INT r;
3043 LONG_PTR style;
3044 static CHAR names[][5] = {"A", "B", "C", "D", "0"};
3045 CHAR buff[10];
3047 hwnd = create_listview_control(LVS_REPORT);
3048 ok(hwnd != NULL, "failed to create a listview window\n");
3050 /* insert some items */
3051 item.mask = LVIF_PARAM | LVIF_STATE;
3052 item.state = LVIS_SELECTED;
3053 item.iItem = 0;
3054 item.iSubItem = 0;
3055 item.lParam = 3;
3056 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3057 expect(0, r);
3059 item.mask = LVIF_PARAM;
3060 item.iItem = 1;
3061 item.iSubItem = 0;
3062 item.lParam = 2;
3063 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3064 expect(1, r);
3066 item.mask = LVIF_STATE | LVIF_PARAM;
3067 item.state = LVIS_SELECTED;
3068 item.iItem = 2;
3069 item.iSubItem = 0;
3070 item.lParam = 4;
3071 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3072 expect(2, r);
3074 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
3075 expect(-1, r);
3077 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3078 expect(2, r);
3080 r = SendMessageA(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare);
3081 expect(TRUE, r);
3083 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3084 expect(2, r);
3085 r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
3086 expect(-1, r);
3087 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED);
3088 expect(0, r);
3089 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED);
3090 expect(LVIS_SELECTED, r);
3091 r = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED);
3092 expect(LVIS_SELECTED, r);
3094 DestroyWindow(hwnd);
3096 /* switch to LVS_SORTASCENDING when some items added */
3097 hwnd = create_listview_control(LVS_REPORT);
3098 ok(hwnd != NULL, "failed to create a listview window\n");
3100 item.mask = LVIF_TEXT;
3101 item.iItem = 0;
3102 item.iSubItem = 0;
3103 item.pszText = names[1];
3104 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3105 expect(0, r);
3107 item.mask = LVIF_TEXT;
3108 item.iItem = 1;
3109 item.iSubItem = 0;
3110 item.pszText = names[2];
3111 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3112 expect(1, r);
3114 item.mask = LVIF_TEXT;
3115 item.iItem = 2;
3116 item.iSubItem = 0;
3117 item.pszText = names[0];
3118 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3119 expect(2, r);
3121 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3122 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3123 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3124 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3126 /* no sorting performed when switched to LVS_SORTASCENDING */
3127 item.mask = LVIF_TEXT;
3128 item.iItem = 0;
3129 item.pszText = buff;
3130 item.cchTextMax = sizeof(buff);
3131 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3132 expect(TRUE, r);
3133 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3135 item.iItem = 1;
3136 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3137 expect(TRUE, r);
3138 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3140 item.iItem = 2;
3141 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3142 expect(TRUE, r);
3143 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3145 /* adding new item doesn't resort list */
3146 item.mask = LVIF_TEXT;
3147 item.iItem = 3;
3148 item.iSubItem = 0;
3149 item.pszText = names[3];
3150 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3151 expect(3, r);
3153 item.mask = LVIF_TEXT;
3154 item.iItem = 0;
3155 item.pszText = buff;
3156 item.cchTextMax = sizeof(buff);
3157 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3158 expect(TRUE, r);
3159 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3161 item.iItem = 1;
3162 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3163 expect(TRUE, r);
3164 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3166 item.iItem = 2;
3167 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3168 expect(TRUE, r);
3169 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3171 item.iItem = 3;
3172 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3173 expect(TRUE, r);
3174 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3176 /* corner case - item should be placed at first position */
3177 item.mask = LVIF_TEXT;
3178 item.iItem = 4;
3179 item.iSubItem = 0;
3180 item.pszText = names[4];
3181 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
3182 expect(0, r);
3184 item.iItem = 0;
3185 item.pszText = buff;
3186 item.cchTextMax = sizeof(buff);
3187 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3188 expect(TRUE, r);
3189 ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
3191 item.iItem = 1;
3192 item.pszText = buff;
3193 item.cchTextMax = sizeof(buff);
3194 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3195 expect(TRUE, r);
3196 ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3198 item.iItem = 2;
3199 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3200 expect(TRUE, r);
3201 ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3203 item.iItem = 3;
3204 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3205 expect(TRUE, r);
3206 ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3208 item.iItem = 4;
3209 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
3210 expect(TRUE, r);
3211 ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3213 DestroyWindow(hwnd);
3216 static void test_ownerdata(void)
3218 static char test_str[] = "test";
3220 HWND hwnd;
3221 LONG_PTR style, ret;
3222 DWORD res;
3223 LVITEMA item;
3225 /* Setting LVS_OWNERDATA after creation leads to crash on older versions < 5.80 */
3226 hwnd = create_listview_control(LVS_REPORT);
3227 ok(hwnd != NULL, "failed to create a listview window\n");
3228 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3229 ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3231 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3233 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3234 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3235 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3236 "try to switch to LVS_OWNERDATA seq", FALSE);
3238 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3239 ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3240 DestroyWindow(hwnd);
3242 /* try to set LVS_OWNERDATA after creation just having it */
3243 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3244 ok(hwnd != NULL, "failed to create a listview window\n");
3245 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3246 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3248 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3250 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA);
3251 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3252 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3253 "try to switch to LVS_OWNERDATA seq", FALSE);
3254 DestroyWindow(hwnd);
3256 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3257 ok(hwnd != NULL, "failed to create a listview window\n");
3258 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3259 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3261 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3263 ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA);
3264 ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3265 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq,
3266 "try to switch to LVS_OWNERDATA seq", FALSE);
3267 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3268 ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3269 DestroyWindow(hwnd);
3271 /* try select an item */
3272 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3273 ok(hwnd != NULL, "failed to create a listview window\n");
3274 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3275 expect(1, res);
3276 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3277 expect(0, res);
3278 memset(&item, 0, sizeof(item));
3279 item.stateMask = LVIS_SELECTED;
3280 item.state = LVIS_SELECTED;
3281 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3282 expect(TRUE, res);
3283 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3284 expect(1, res);
3285 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3286 expect(1, res);
3287 DestroyWindow(hwnd);
3289 /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3290 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3291 ok(hwnd != NULL, "failed to create a listview window\n");
3292 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3293 expect(1, res);
3294 res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
3295 expect(1, res);
3296 memset(&item, 0, sizeof(item));
3297 item.mask = LVIF_STATE;
3298 item.iItem = 0;
3299 item.stateMask = LVIS_SELECTED;
3300 item.state = LVIS_SELECTED;
3301 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
3302 expect(FALSE, res);
3303 memset(&item, 0, sizeof(item));
3304 item.pszText = test_str;
3305 res = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3306 expect(FALSE, res);
3307 DestroyWindow(hwnd);
3309 /* check notifications after focused/selected changed */
3310 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3311 ok(hwnd != NULL, "failed to create a listview window\n");
3312 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3313 expect(1, res);
3315 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3317 memset(&item, 0, sizeof(item));
3318 item.stateMask = LVIS_SELECTED;
3319 item.state = LVIS_SELECTED;
3320 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3321 expect(TRUE, res);
3323 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3324 "ownerdata select notification", TRUE);
3326 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3328 memset(&item, 0, sizeof(item));
3329 item.stateMask = LVIS_FOCUSED;
3330 item.state = LVIS_FOCUSED;
3331 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3332 expect(TRUE, res);
3334 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_select_focus_parent_seq,
3335 "ownerdata focus notification", TRUE);
3337 /* select all, check notifications */
3338 item.stateMask = LVIS_SELECTED;
3339 item.state = 0;
3340 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3341 expect(TRUE, res);
3343 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3345 item.stateMask = LVIS_SELECTED;
3346 item.state = LVIS_SELECTED;
3348 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3349 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3350 expect(TRUE, res);
3351 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3352 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3353 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3354 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3355 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3356 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3357 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3359 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3360 "ownerdata select all notification", FALSE);
3362 /* select all again, note that all items are selected already */
3363 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3364 item.stateMask = LVIS_SELECTED;
3365 item.state = LVIS_SELECTED;
3367 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3368 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3369 expect(TRUE, res);
3370 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3371 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3372 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
3373 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3374 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3375 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3376 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3378 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3379 "ownerdata select all notification", FALSE);
3381 /* deselect all */
3382 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3383 item.stateMask = LVIS_SELECTED;
3384 item.state = 0;
3386 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3387 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3388 expect(TRUE, res);
3389 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3390 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3391 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3392 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3393 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3394 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3395 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3397 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3398 "ownerdata deselect all notification", TRUE);
3400 /* nothing selected, deselect all again */
3401 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3402 item.stateMask = LVIS_SELECTED;
3403 item.state = 0;
3405 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3406 expect(TRUE, res);
3408 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "ownerdata deselect all notification", FALSE);
3410 /* select one, then deselect all */
3411 item.stateMask = LVIS_SELECTED;
3412 item.state = LVIS_SELECTED;
3413 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3414 expect(TRUE, res);
3415 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3416 item.stateMask = LVIS_SELECTED;
3417 item.state = 0;
3419 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3420 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3421 expect(TRUE, res);
3422 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3423 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3424 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3425 ok(g_nmlistview.uOldState == LVIS_SELECTED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3426 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3427 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3428 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3430 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_deselect_all_parent_seq,
3431 "ownerdata select all notification", TRUE);
3433 /* remove focused, try to focus all */
3434 item.stateMask = LVIS_FOCUSED;
3435 item.state = LVIS_FOCUSED;
3436 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3437 expect(TRUE, res);
3438 item.stateMask = LVIS_FOCUSED;
3439 item.state = 0;
3440 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3441 expect(TRUE, res);
3442 item.stateMask = LVIS_FOCUSED;
3443 res = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
3444 expect(0, res);
3446 /* setting all to focused returns failure value */
3447 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3448 item.stateMask = LVIS_FOCUSED;
3449 item.state = LVIS_FOCUSED;
3451 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3452 expect(FALSE, res);
3454 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3455 "ownerdata focus all notification", FALSE);
3457 /* focus single item, remove all */
3458 item.stateMask = LVIS_FOCUSED;
3459 item.state = LVIS_FOCUSED;
3460 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3461 expect(TRUE, res);
3462 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3463 item.stateMask = LVIS_FOCUSED;
3464 item.state = 0;
3466 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3467 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3468 expect(TRUE, res);
3469 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3470 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3471 ok(g_nmlistview.uNewState == 0, "got new state 0x%08x\n", g_nmlistview.uNewState);
3472 ok(g_nmlistview.uOldState == LVIS_FOCUSED, "got old state 0x%08x\n", g_nmlistview.uOldState);
3473 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3474 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3475 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3477 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_defocus_all_parent_seq,
3478 "ownerdata remove focus all notification", TRUE);
3480 /* set all cut */
3481 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3482 item.stateMask = LVIS_CUT;
3483 item.state = LVIS_CUT;
3485 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3486 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3487 expect(TRUE, res);
3488 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3489 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3490 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3491 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3492 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3493 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3494 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3496 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3497 "ownerdata cut all notification", FALSE);
3499 /* all marked cut, try again */
3500 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3501 item.stateMask = LVIS_CUT;
3502 item.state = LVIS_CUT;
3504 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
3505 res = SendMessageA(hwnd, LVM_SETITEMSTATE, -1, (LPARAM)&item);
3506 expect(TRUE, res);
3507 ok(g_nmlistview.iItem == -1, "got item %d\n", g_nmlistview.iItem);
3508 ok(g_nmlistview.iSubItem == 0, "got subitem %d\n", g_nmlistview.iSubItem);
3509 ok(g_nmlistview.uNewState == LVIS_CUT, "got new state 0x%08x\n", g_nmlistview.uNewState);
3510 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
3511 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
3512 ok(g_nmlistview.ptAction.x == 0 && g_nmlistview.ptAction.y == 0, "got wrong ptAction value\n");
3513 ok(g_nmlistview.lParam == 0, "got wrong lparam\n");
3515 ok_sequence(sequences, PARENT_SEQ_INDEX, ownerdata_setstate_all_parent_seq,
3516 "ownerdata cut all notification #2", FALSE);
3518 DestroyWindow(hwnd);
3520 /* check notifications on LVM_GETITEM */
3521 /* zero callback mask */
3522 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3523 ok(hwnd != NULL, "failed to create a listview window\n");
3524 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3525 expect(1, res);
3527 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3529 memset(&item, 0, sizeof(item));
3530 item.stateMask = LVIS_SELECTED;
3531 item.mask = LVIF_STATE;
3532 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3533 expect(TRUE, res);
3535 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3536 "ownerdata getitem selected state 1", FALSE);
3538 /* non zero callback mask but not we asking for */
3539 res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
3540 expect(TRUE, res);
3542 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3544 memset(&item, 0, sizeof(item));
3545 item.stateMask = LVIS_SELECTED;
3546 item.mask = LVIF_STATE;
3547 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3548 expect(TRUE, res);
3550 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3551 "ownerdata getitem selected state 2", FALSE);
3553 /* LVIS_OVERLAYMASK callback mask, asking for index */
3554 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3556 memset(&item, 0, sizeof(item));
3557 item.stateMask = LVIS_OVERLAYMASK;
3558 item.mask = LVIF_STATE;
3559 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3560 expect(TRUE, res);
3562 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
3563 "ownerdata getitem selected state 2", FALSE);
3565 DestroyWindow(hwnd);
3567 /* LVS_SORTASCENDING/LVS_SORTDESCENDING aren't compatible with LVS_OWNERDATA */
3568 hwnd = create_listview_control(LVS_OWNERDATA | LVS_SORTASCENDING | LVS_REPORT);
3569 ok(hwnd != NULL, "failed to create a listview window\n");
3570 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3571 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3572 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3573 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_SORTASCENDING);
3574 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3575 ok(!(style & LVS_SORTASCENDING), "Expected LVS_SORTASCENDING not set\n");
3576 DestroyWindow(hwnd);
3577 /* apparently it's allowed to switch these style on after creation */
3578 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3579 ok(hwnd != NULL, "failed to create a listview window\n");
3580 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3581 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3582 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING);
3583 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3584 ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
3585 DestroyWindow(hwnd);
3587 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3588 ok(hwnd != NULL, "failed to create a listview window\n");
3589 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3590 ok(style & LVS_OWNERDATA, "Expected LVS_OWNERDATA\n");
3591 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTDESCENDING);
3592 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3593 ok(style & LVS_SORTDESCENDING, "Expected LVS_SORTDESCENDING to be set\n");
3594 DestroyWindow(hwnd);
3596 /* The focused item is updated after the invalidation */
3597 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3598 ok(hwnd != NULL, "failed to create a listview window\n");
3599 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 3, 0);
3600 expect(TRUE, res);
3602 memset(&item, 0, sizeof(item));
3603 item.stateMask = LVIS_FOCUSED;
3604 item.state = LVIS_FOCUSED;
3605 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3606 expect(TRUE, res);
3608 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3609 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
3610 expect(TRUE, res);
3611 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3612 "ownerdata setitemcount", FALSE);
3614 res = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
3615 expect(-1, res);
3616 DestroyWindow(hwnd);
3619 static void test_ownerdata_multiselect(void)
3621 HWND hwnd;
3622 DWORD res;
3623 LVITEMA item;
3624 unsigned int i;
3625 char buf[256];
3627 static const struct
3629 BOOL hold_shift;
3630 BOOL hold_control;
3631 UINT press_key;
3632 UINT selected_count;
3633 const char *context;
3634 const struct message *expected;
3635 BOOL todo;
3637 key_tests[] =
3639 /* First down then up */
3640 { TRUE, FALSE, VK_DOWN, 2, "select multiple via SHIFT+DOWN",
3641 ownerdata_multiselect_select_0_to_1_odstatechanged_seq, FALSE },
3642 { TRUE, FALSE, VK_UP, 1, "select one item via SHIFT+UP",
3643 ownerdata_multiselect_select_0_modkey_odstatechanged_seq, TRUE },
3644 { TRUE, TRUE, VK_DOWN, 2, "select multiple via SHIFT+CONTROL+DOWN",
3645 ownerdata_multiselect_select_0_to_1_odstatechanged_seq, FALSE },
3646 { TRUE, TRUE, VK_UP, 1, "select one item via SHIFT+CONTROL+UP",
3647 ownerdata_multiselect_select_0_modkey_odstatechanged_seq, TRUE },
3648 { FALSE, TRUE, VK_DOWN, 1, "keep selection but move cursor via CONTROL+DOWN",
3649 ownerdata_multiselect_move_0_to_1_odstatechanged_seq, FALSE },
3650 { TRUE, TRUE, VK_DOWN, 3, "select multiple after skip via SHIFT+CONTROL+DOWN",
3651 ownerdata_multiselect_select_0_to_2_odstatechanged_seq, FALSE },
3652 { FALSE, FALSE, VK_DOWN, 1, "deselect all, select item 3 via DOWN",
3653 ownerdata_multiselect_select_3_odstatechanged_seq, FALSE },
3654 /* First up then down */
3655 { TRUE, FALSE, VK_UP, 2, "select multiple via SHIFT+UP",
3656 ownerdata_multiselect_select_3_to_2_odstatechanged_seq, FALSE },
3657 { TRUE, FALSE, VK_DOWN, 1, "select one item via SHIFT+DOWN",
3658 ownerdata_multiselect_select_3_modkey_odstatechanged_seq, TRUE },
3659 { TRUE, TRUE, VK_UP, 2, "select multiple via SHIFT+CONTROL+UP",
3660 ownerdata_multiselect_select_3_to_2_odstatechanged_seq, FALSE },
3661 { TRUE, TRUE, VK_DOWN, 1, "select one item via SHIFT+CONTROL+DOWN",
3662 ownerdata_multiselect_select_3_modkey_odstatechanged_seq, TRUE },
3663 { FALSE, TRUE, VK_UP, 1, "keep selection but move cursor via CONTROL+UP",
3664 ownerdata_multiselect_move_3_to_2_odstatechanged_seq, FALSE },
3665 { TRUE, TRUE, VK_UP, 3, "select multiple after skip via SHIFT+CONTROL+UP",
3666 ownerdata_multiselect_select_3_to_1_odstatechanged_seq, FALSE },
3667 { FALSE, FALSE, VK_UP, 1, "deselect all, select item 0 via UP",
3668 ownerdata_multiselect_select_0_odstatechanged_seq, FALSE },
3671 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3672 ok(hwnd != NULL, "failed to create a listview window\n");
3673 res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 20, 0);
3674 expect(1, res);
3675 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3676 expect(0, res);
3678 /* Select and focus the first row */
3679 memset(&item, 0, sizeof(item));
3680 item.state = LVIS_SELECTED | LVIS_FOCUSED;
3681 item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3682 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
3683 expect(TRUE, res);
3684 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3685 expect(1, res);
3686 res = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, 0);
3687 expect(0, res);
3689 /* Select/deselect rows using UP/DOWN and SHIFT/CONTROL keys */
3690 for (i = 0; i < ARRAY_SIZE(key_tests); i++)
3692 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3694 if (key_tests[i].hold_shift)
3695 hold_key(VK_SHIFT);
3696 if (key_tests[i].hold_control)
3697 hold_key(VK_CONTROL);
3699 res = SendMessageA(hwnd, WM_KEYDOWN, key_tests[i].press_key, 0);
3700 expect(0, res);
3701 sprintf(buf, "ownerdata multiselect: %s", key_tests[i].context);
3702 ok_sequence(sequences, PARENT_ODSTATECHANGED_SEQ_INDEX, key_tests[i].expected,
3703 buf, key_tests[i].todo);
3704 res = SendMessageA(hwnd, WM_KEYUP, key_tests[i].press_key, 0);
3705 expect(0, res);
3707 res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
3708 expect(key_tests[i].selected_count, res);
3710 if (key_tests[i].hold_shift)
3711 release_key(VK_SHIFT);
3712 if (key_tests[i].hold_control)
3713 release_key(VK_CONTROL);
3716 DestroyWindow(hwnd);
3719 static void test_norecompute(void)
3721 static CHAR testA[] = "test";
3722 CHAR buff[10];
3723 LVITEMA item;
3724 HWND hwnd;
3725 DWORD res;
3727 /* self containing control */
3728 hwnd = create_listview_control(LVS_REPORT);
3729 ok(hwnd != NULL, "failed to create a listview window\n");
3730 memset(&item, 0, sizeof(item));
3731 item.mask = LVIF_TEXT | LVIF_STATE;
3732 item.iItem = 0;
3733 item.stateMask = LVIS_SELECTED;
3734 item.state = LVIS_SELECTED;
3735 item.pszText = testA;
3736 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3737 expect(0, res);
3738 /* retrieve with LVIF_NORECOMPUTE */
3739 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3740 item.iItem = 0;
3741 item.pszText = buff;
3742 item.cchTextMax = ARRAY_SIZE(buff);
3743 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3744 expect(TRUE, res);
3745 ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
3747 item.mask = LVIF_TEXT;
3748 item.iItem = 1;
3749 item.pszText = LPSTR_TEXTCALLBACKA;
3750 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3751 expect(1, res);
3753 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3754 item.iItem = 1;
3755 item.pszText = buff;
3756 item.cchTextMax = ARRAY_SIZE(buff);
3758 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3759 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3760 expect(TRUE, res);
3761 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3762 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3763 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE);
3765 DestroyWindow(hwnd);
3767 /* LVS_OWNERDATA */
3768 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3769 ok(hwnd != NULL, "failed to create a listview window\n");
3771 item.mask = LVIF_STATE;
3772 item.stateMask = LVIS_SELECTED;
3773 item.state = LVIS_SELECTED;
3774 item.iItem = 0;
3775 res = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
3776 expect(0, res);
3778 item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
3779 item.iItem = 0;
3780 item.pszText = buff;
3781 item.cchTextMax = ARRAY_SIZE(buff);
3782 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3783 res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
3784 expect(TRUE, res);
3785 ok(item.pszText == LPSTR_TEXTCALLBACKA, "Expected (%p), got (%p)\n",
3786 LPSTR_TEXTCALLBACKA, (VOID*)item.pszText);
3787 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE);
3789 DestroyWindow(hwnd);
3792 static void test_nosortheader(void)
3794 HWND hwnd, header;
3795 LONG_PTR style;
3797 hwnd = create_listview_control(LVS_REPORT);
3798 ok(hwnd != NULL, "failed to create a listview window\n");
3800 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3801 ok(IsWindow(header), "header expected\n");
3803 style = GetWindowLongPtrA(header, GWL_STYLE);
3804 ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n");
3806 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3807 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER);
3808 /* HDS_BUTTONS retained */
3809 style = GetWindowLongPtrA(header, GWL_STYLE);
3810 ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n");
3812 DestroyWindow(hwnd);
3814 /* create with LVS_NOSORTHEADER */
3815 hwnd = create_listview_control(LVS_NOSORTHEADER | LVS_REPORT);
3816 ok(hwnd != NULL, "failed to create a listview window\n");
3818 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
3819 ok(IsWindow(header), "header expected\n");
3821 style = GetWindowLongPtrA(header, GWL_STYLE);
3822 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3824 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3825 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER);
3826 /* not changed here */
3827 style = GetWindowLongPtrA(header, GWL_STYLE);
3828 ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n");
3830 DestroyWindow(hwnd);
3833 static void test_setredraw(void)
3835 HWND hwnd;
3836 DWORD_PTR style;
3837 DWORD ret;
3838 HDC hdc;
3839 RECT rect;
3841 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
3842 ok(hwnd != NULL, "failed to create a listview window\n");
3844 /* Passing WM_SETREDRAW to DefWinProc removes WS_VISIBLE.
3845 ListView seems to handle it internally without DefWinProc */
3847 /* default value first */
3848 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3849 expect(0, ret);
3850 /* disable */
3851 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3852 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3853 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3854 expect(0, ret);
3855 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
3856 ok(style & WS_VISIBLE, "Expected WS_VISIBLE to be set\n");
3857 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3858 expect(0, ret);
3860 /* check update rect after redrawing */
3861 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3862 expect(0, ret);
3863 InvalidateRect(hwnd, NULL, FALSE);
3864 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
3865 rect.right = rect.bottom = 1;
3866 GetUpdateRect(hwnd, &rect, FALSE);
3867 expect(0, rect.right);
3868 expect(0, rect.bottom);
3870 /* WM_ERASEBKGND */
3871 hdc = GetWindowDC(hwndparent);
3872 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3873 expect(TRUE, ret);
3874 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3875 expect(0, ret);
3876 ret = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
3877 expect(TRUE, ret);
3878 ret = SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
3879 expect(0, ret);
3880 ReleaseDC(hwndparent, hdc);
3882 /* check notification messages to show that repainting is disabled */
3883 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
3884 expect(TRUE, ret);
3885 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3886 expect(0, ret);
3887 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3889 InvalidateRect(hwnd, NULL, TRUE);
3890 UpdateWindow(hwnd);
3891 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3892 "redraw after WM_SETREDRAW (FALSE)", FALSE);
3894 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, CLR_NONE);
3895 expect(TRUE, ret);
3896 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3897 InvalidateRect(hwnd, NULL, TRUE);
3898 UpdateWindow(hwnd);
3899 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
3900 "redraw after WM_SETREDRAW (FALSE) with CLR_NONE bkgnd", FALSE);
3902 /* message isn't forwarded to header */
3903 subclass_header(hwnd);
3904 flush_sequences(sequences, NUM_MSG_SEQUENCES);
3905 ret = SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
3906 expect(0, ret);
3907 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, setredraw_seq,
3908 "WM_SETREDRAW: not forwarded to header", FALSE);
3910 DestroyWindow(hwnd);
3913 static void test_hittest(void)
3915 HWND hwnd;
3916 DWORD r;
3917 RECT bounds;
3918 LVITEMA item;
3919 static CHAR text[] = "1234567890ABCDEFGHIJKLMNOPQRST";
3920 POINT pos;
3921 INT x, y, i;
3922 WORD vert;
3923 HIMAGELIST himl, himl2;
3924 HBITMAP hbmp;
3926 hwnd = create_listview_control(LVS_REPORT);
3927 ok(hwnd != NULL, "failed to create a listview window\n");
3929 /* LVS_REPORT with a single subitem (2 columns) */
3930 insert_column(hwnd, 0);
3931 insert_column(hwnd, 1);
3932 insert_item(hwnd, 0);
3934 item.iSubItem = 0;
3935 /* the only purpose of that line is to be as long as a half item rect */
3936 item.pszText = text;
3937 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
3938 expect(TRUE, r);
3940 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
3941 expect(TRUE, r);
3942 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
3943 expect(TRUE, r);
3945 SetRect(&bounds, LVIR_BOUNDS, 0, 0, 0);
3946 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&bounds);
3947 expect(1, r);
3948 ok(bounds.bottom - bounds.top > 0, "Expected non zero item height\n");
3949 ok(bounds.right - bounds.left > 0, "Expected non zero item width\n");
3950 r = SendMessageA(hwnd, LVM_GETITEMSPACING, TRUE, 0);
3951 vert = HIWORD(r);
3952 ok(bounds.bottom - bounds.top == vert,
3953 "Vertical spacing inconsistent (%ld != %d)\n", bounds.bottom - bounds.top, vert);
3954 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pos);
3955 expect(TRUE, r);
3957 /* LVS_EX_FULLROWSELECT not set, no icons attached */
3959 /* outside columns by x position - valid is [0, 199] */
3960 x = -1;
3961 y = pos.y + (bounds.bottom - bounds.top) / 2;
3962 test_lvm_hittest(hwnd, x, y, -1, LVHT_TOLEFT, 0, FALSE, FALSE);
3963 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3965 x = pos.x + 50; /* column half width */
3966 y = pos.y + (bounds.bottom - bounds.top) / 2;
3967 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMLABEL, 0, FALSE, FALSE);
3968 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3969 x = pos.x + 150; /* outside column */
3970 y = pos.y + (bounds.bottom - bounds.top) / 2;
3971 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3972 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3973 y = (bounds.bottom - bounds.top) / 2;
3974 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3975 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
3976 /* outside possible client rectangle (to right) */
3977 x = pos.x + 500;
3978 y = pos.y + (bounds.bottom - bounds.top) / 2;
3979 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
3980 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3981 y = (bounds.bottom - bounds.top) / 2;
3982 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
3983 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3984 /* subitem returned with -1 item too */
3985 x = pos.x + 150;
3986 y = bounds.top - vert;
3987 test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3988 test_lvm_subitemhittest(hwnd, x, y - vert + 1, -1, 1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
3989 /* return values appear to underflow with negative indices */
3990 i = -2;
3991 y = y - vert;
3992 while (i > -10) {
3993 test_lvm_subitemhittest(hwnd, x, y, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3994 test_lvm_subitemhittest(hwnd, x, y - vert + 1, i, 1, LVHT_ONITEMLABEL, TRUE, FALSE, TRUE);
3995 y = y - vert;
3996 i--;
3998 /* parent client area is 100x100 by default */
3999 MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
4000 x = pos.x + 150; /* outside column */
4001 y = pos.y + (bounds.bottom - bounds.top) / 2;
4002 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, FALSE);
4003 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4004 y = (bounds.bottom - bounds.top) / 2;
4005 test_lvm_hittest(hwnd, x, y, -1, LVHT_NOWHERE, 0, FALSE, TRUE);
4006 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4007 /* the same with LVS_EX_FULLROWSELECT */
4008 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
4009 x = pos.x + 150; /* outside column */
4010 y = pos.y + (bounds.bottom - bounds.top) / 2;
4011 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEM, LVHT_ONITEMLABEL, FALSE, FALSE);
4012 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4013 y = (bounds.bottom - bounds.top) / 2;
4014 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4015 MoveWindow(hwnd, 0, 0, 100, 100, FALSE);
4016 x = pos.x + 150; /* outside column */
4017 y = pos.y + (bounds.bottom - bounds.top) / 2;
4018 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
4019 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4020 y = (bounds.bottom - bounds.top) / 2;
4021 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
4022 test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE);
4023 /* outside possible client rectangle (to right) */
4024 x = pos.x + 500;
4025 y = pos.y + (bounds.bottom - bounds.top) / 2;
4026 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, FALSE);
4027 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
4028 y = (bounds.bottom - bounds.top) / 2;
4029 test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, 0, FALSE, TRUE);
4030 test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE);
4031 /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
4032 himl = pImageList_Create(16, 16, 0, 4, 4);
4033 ok(himl != NULL, "failed to create imagelist\n");
4034 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
4035 ok(hbmp != NULL, "failed to create bitmap\n");
4036 r = pImageList_Add(himl, hbmp, 0);
4037 ok(r == 0, "should be zero\n");
4038 hbmp = CreateBitmap(16, 16, 1, 1, NULL);
4039 ok(hbmp != NULL, "failed to create bitmap\n");
4040 r = pImageList_Add(himl, hbmp, 0);
4041 ok(r == 1, "should be one\n");
4043 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4044 expect(0, r);
4046 item.mask = LVIF_IMAGE;
4047 item.iImage = 0;
4048 item.iItem = 0;
4049 item.iSubItem = 0;
4050 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4051 expect(TRUE, r);
4052 /* on state icon */
4053 x = pos.x + 8;
4054 y = pos.y + (bounds.bottom - bounds.top) / 2;
4055 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
4056 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4057 y = (bounds.bottom - bounds.top) / 2;
4058 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4060 /* state icons indices are 1 based, check with valid index */
4061 item.mask = LVIF_STATE;
4062 item.state = INDEXTOSTATEIMAGEMASK(1);
4063 item.stateMask = LVIS_STATEIMAGEMASK;
4064 item.iItem = 0;
4065 item.iSubItem = 0;
4066 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4067 expect(TRUE, r);
4068 /* on state icon */
4069 x = pos.x + 8;
4070 y = pos.y + (bounds.bottom - bounds.top) / 2;
4071 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMSTATEICON, 0, FALSE, FALSE);
4072 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4073 y = (bounds.bottom - bounds.top) / 2;
4074 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMSTATEICON, FALSE, FALSE, FALSE);
4076 himl2 = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4077 ok(himl2 == himl, "should return handle\n");
4079 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4080 expect(0, r);
4081 /* on item icon */
4082 x = pos.x + 8;
4083 y = pos.y + (bounds.bottom - bounds.top) / 2;
4084 test_lvm_hittest(hwnd, x, y, 0, LVHT_ONITEMICON, 0, FALSE, FALSE);
4085 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
4086 y = (bounds.bottom - bounds.top) / 2;
4087 test_lvm_subitemhittest(hwnd, x, y, 0, 0, LVHT_ONITEMICON, FALSE, FALSE, FALSE);
4089 DestroyWindow(hwnd);
4092 static void test_getviewrect(void)
4094 HWND hwnd;
4095 DWORD r;
4096 RECT rect;
4097 LVITEMA item;
4099 hwnd = create_listview_control(LVS_REPORT);
4100 ok(hwnd != NULL, "failed to create a listview window\n");
4102 /* empty */
4103 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4104 expect(TRUE, r);
4106 insert_column(hwnd, 0);
4107 insert_column(hwnd, 1);
4109 memset(&item, 0, sizeof(item));
4110 item.iItem = 0;
4111 item.iSubItem = 0;
4112 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4113 ok(!r, "got %ld\n", r);
4115 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
4116 expect(TRUE, r);
4117 r = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(120, 0));
4118 expect(TRUE, r);
4120 SetRect(&rect, -1, -1, -1, -1);
4121 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4122 expect(TRUE, r);
4123 /* left is set to (2e31-1) - XP SP2 */
4124 expect(0, rect.right);
4125 expect(0, rect.top);
4126 expect(0, rect.bottom);
4128 /* switch to LVS_ICON */
4129 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_REPORT);
4131 SetRect(&rect, -1, -1, -1, -1);
4132 r = SendMessageA(hwnd, LVM_GETVIEWRECT, 0, (LPARAM)&rect);
4133 expect(TRUE, r);
4134 expect(0, rect.left);
4135 expect(0, rect.top);
4136 /* precise value differs for 2k, XP and Vista */
4137 ok(rect.bottom > 0, "Expected positive bottom value, got %ld\n", rect.bottom);
4138 ok(rect.right > 0, "Expected positive right value, got %ld\n", rect.right);
4140 DestroyWindow(hwnd);
4143 static void test_getitemposition(void)
4145 HWND hwnd, header;
4146 DWORD r;
4147 POINT pt;
4148 RECT rect;
4150 hwnd = create_listview_control(LVS_REPORT);
4151 ok(hwnd != NULL, "failed to create a listview window\n");
4152 header = subclass_header(hwnd);
4154 /* LVS_REPORT, single item, no columns added */
4155 insert_item(hwnd, 0);
4157 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4159 pt.x = pt.y = -1;
4160 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4161 expect(TRUE, r);
4162 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq1, "get item position 1", FALSE);
4164 /* LVS_REPORT, single item, single column */
4165 insert_column(hwnd, 0);
4167 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4169 pt.x = pt.y = -1;
4170 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4171 expect(TRUE, r);
4172 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getitemposition_seq2, "get item position 2", TRUE);
4174 SetRectEmpty(&rect);
4175 r = SendMessageA(header, HDM_GETITEMRECT, 0, (LPARAM)&rect);
4176 ok(r, "got %ld\n", r);
4177 /* some padding? */
4178 expect(2, pt.x);
4179 /* offset by header height */
4180 expect(rect.bottom - rect.top, pt.y);
4182 DestroyWindow(hwnd);
4185 static void test_getitemrect(void)
4187 HWND hwnd;
4188 HIMAGELIST himl, himl_ret;
4189 HBITMAP hbm;
4190 RECT rect;
4191 DWORD r;
4192 LVITEMA item;
4193 LVCOLUMNA col;
4194 INT order[2];
4195 POINT pt;
4197 /* rectangle isn't empty for empty text items */
4198 hwnd = create_listview_control(LVS_LIST);
4199 memset(&item, 0, sizeof(item));
4200 item.mask = 0;
4201 item.iItem = 0;
4202 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4203 expect(0, r);
4204 rect.left = LVIR_LABEL;
4205 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4206 expect(TRUE, r);
4207 expect(0, rect.left);
4208 expect(0, rect.top);
4209 /* estimate it as width / height ratio */
4210 todo_wine
4211 ok((rect.right / rect.bottom) >= 5, "got right %ld, bottom %ld\n", rect.right, rect.bottom);
4212 DestroyWindow(hwnd);
4214 hwnd = create_listview_control(LVS_REPORT);
4215 ok(hwnd != NULL, "failed to create a listview window\n");
4217 /* empty item */
4218 memset(&item, 0, sizeof(item));
4219 item.iItem = 0;
4220 item.iSubItem = 0;
4221 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4222 expect(0, r);
4224 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4225 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4226 expect(TRUE, r);
4228 /* zero width rectangle with no padding */
4229 expect(0, rect.left);
4230 expect(0, rect.right);
4232 insert_column(hwnd, 0);
4233 insert_column(hwnd, 1);
4235 col.mask = LVCF_WIDTH;
4236 col.cx = 50;
4237 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 0, (LPARAM)&col);
4238 expect(TRUE, r);
4240 col.mask = LVCF_WIDTH;
4241 col.cx = 100;
4242 r = SendMessageA(hwnd, LVM_SETCOLUMNA, 1, (LPARAM)&col);
4243 expect(TRUE, r);
4245 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4246 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4247 expect(TRUE, r);
4249 /* still no left padding */
4250 expect(0, rect.left);
4251 expect(150, rect.right);
4253 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4254 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4255 expect(TRUE, r);
4256 /* padding */
4257 expect(2, rect.left);
4259 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4260 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4261 expect(TRUE, r);
4262 /* padding, column width */
4263 expect(2, rect.left);
4264 expect(50, rect.right);
4266 /* no icons attached */
4267 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4268 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4269 expect(TRUE, r);
4270 /* padding */
4271 expect(2, rect.left);
4272 expect(2, rect.right);
4274 /* change order */
4275 order[0] = 1; order[1] = 0;
4276 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4277 expect(TRUE, r);
4278 pt.x = -1;
4279 r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM)&pt);
4280 expect(TRUE, r);
4281 /* 1 indexed column width + padding */
4282 expect(102, pt.x);
4283 /* rect is at zero too */
4284 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4285 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4286 expect(TRUE, r);
4287 expect(0, rect.left);
4288 /* just width sum */
4289 expect(150, rect.right);
4291 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4292 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4293 expect(TRUE, r);
4294 /* column width + padding */
4295 expect(102, rect.left);
4297 /* back to initial order */
4298 order[0] = 0; order[1] = 1;
4299 r = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order);
4300 expect(TRUE, r);
4302 /* state icons */
4303 himl = pImageList_Create(16, 16, 0, 2, 2);
4304 ok(himl != NULL, "failed to create imagelist\n");
4305 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4306 ok(hbm != NULL, "failed to create bitmap\n");
4307 r = pImageList_Add(himl, hbm, 0);
4308 expect(0, r);
4309 hbm = CreateBitmap(16, 16, 1, 1, NULL);
4310 ok(hbm != NULL, "failed to create bitmap\n");
4311 r = pImageList_Add(himl, hbm, 0);
4312 expect(1, r);
4314 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl);
4315 expect(0, r);
4317 item.mask = LVIF_STATE;
4318 item.state = INDEXTOSTATEIMAGEMASK(1);
4319 item.stateMask = LVIS_STATEIMAGEMASK;
4320 item.iItem = 0;
4321 item.iSubItem = 0;
4322 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4323 expect(TRUE, r);
4325 /* icon bounds */
4326 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4327 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4328 expect(TRUE, r);
4329 /* padding + stateicon width */
4330 expect(18, rect.left);
4331 expect(18, rect.right);
4332 /* label bounds */
4333 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4334 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4335 expect(TRUE, r);
4336 /* padding + stateicon width -> column width */
4337 expect(18, rect.left);
4338 expect(50, rect.right);
4340 himl_ret = (HIMAGELIST)SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, 0);
4341 ok(himl_ret == himl, "got %p, expected %p\n", himl_ret, himl);
4343 r = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
4344 expect(0, r);
4346 item.mask = LVIF_STATE | LVIF_IMAGE;
4347 item.iImage = 1;
4348 item.state = 0;
4349 item.stateMask = ~0;
4350 item.iItem = 0;
4351 item.iSubItem = 0;
4352 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4353 expect(TRUE, r);
4355 /* icon bounds */
4356 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4357 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4358 expect(TRUE, r);
4359 /* padding, icon width */
4360 expect(2, rect.left);
4361 expect(18, rect.right);
4362 /* label bounds */
4363 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4364 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4365 expect(TRUE, r);
4366 /* padding + icon width -> column width */
4367 expect(18, rect.left);
4368 expect(50, rect.right);
4370 /* select bounds */
4371 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4372 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4373 expect(TRUE, r);
4374 /* padding, column width */
4375 expect(2, rect.left);
4376 expect(50, rect.right);
4378 /* try with indentation */
4379 item.mask = LVIF_INDENT;
4380 item.iIndent = 1;
4381 item.iItem = 0;
4382 item.iSubItem = 0;
4383 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
4384 expect(TRUE, r);
4386 /* bounds */
4387 SetRect(&rect, LVIR_BOUNDS, -1, -1, -1);
4388 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4389 expect(TRUE, r);
4390 /* padding + 1 icon width, column width */
4391 expect(0, rect.left);
4392 expect(150, rect.right);
4394 /* select bounds */
4395 SetRect(&rect, LVIR_SELECTBOUNDS, -1, -1, -1);
4396 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4397 expect(TRUE, r);
4398 /* padding + 1 icon width, column width */
4399 expect(2 + 16, rect.left);
4400 expect(50, rect.right);
4402 /* label bounds */
4403 SetRect(&rect, LVIR_LABEL, -1, -1, -1);
4404 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4405 expect(TRUE, r);
4406 /* padding + 2 icon widths, column width */
4407 expect(2 + 16*2, rect.left);
4408 expect(50, rect.right);
4410 /* icon bounds */
4411 SetRect(&rect, LVIR_ICON, -1, -1, -1);
4412 r = SendMessageA(hwnd, LVM_GETITEMRECT, 0, (LPARAM)&rect);
4413 expect(TRUE, r);
4414 /* padding + 1 icon width indentation, icon width */
4415 expect(2 + 16, rect.left);
4416 expect(34, rect.right);
4418 DestroyWindow(hwnd);
4421 static void test_editbox(void)
4423 static CHAR testitemA[] = "testitem";
4424 static CHAR testitem1A[] = "testitem_quitelongname";
4425 static CHAR testitem2A[] = "testITEM_quitelongname";
4426 static CHAR buffer[25];
4427 HWND hwnd, hwndedit, hwndedit2, header;
4428 LVITEMA item;
4429 INT r;
4431 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4432 ok(hwnd != NULL, "failed to create a listview window\n");
4434 insert_column(hwnd, 0);
4436 memset(&item, 0, sizeof(item));
4437 item.mask = LVIF_TEXT;
4438 item.pszText = testitemA;
4439 item.iItem = 0;
4440 item.iSubItem = 0;
4441 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4442 expect(0, r);
4444 /* test notifications without edit created */
4445 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4446 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)0xdeadbeef);
4447 expect(0, r);
4448 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4449 "edit box WM_COMMAND (EN_SETFOCUS), no edit created", FALSE);
4450 /* same thing but with valid window */
4451 hwndedit = CreateWindowA(WC_EDITA, "Test edit", WS_VISIBLE | WS_CHILD, 0, 0, 20,
4452 10, hwnd, (HMENU)1, (HINSTANCE)GetWindowLongPtrA(hwnd, GWLP_HINSTANCE), 0);
4453 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4454 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndedit);
4455 expect(0, r);
4456 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4457 "edit box WM_COMMAND (EN_SETFOCUS), no edit created #2", FALSE);
4458 DestroyWindow(hwndedit);
4460 /* setting focus is necessary */
4461 SetFocus(hwnd);
4462 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4463 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4465 /* test children Z-order after Edit box created */
4466 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4467 ok(IsWindow(header), "Expected header to be created\n");
4468 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4469 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4471 /* modify initial string */
4472 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4473 expect(TRUE, r);
4475 /* edit window is resized and repositioned,
4476 check again for Z-order - it should be preserved */
4477 ok(GetTopWindow(hwnd) == header, "Expected header to be on top\n");
4478 ok(GetNextWindow(header, GW_HWNDNEXT) == hwndedit, "got %p\n", GetNextWindow(header, GW_HWNDNEXT));
4480 /* return focus to listview */
4481 SetFocus(hwnd);
4483 memset(&item, 0, sizeof(item));
4484 item.mask = LVIF_TEXT;
4485 item.pszText = buffer;
4486 item.cchTextMax = sizeof(buffer);
4487 item.iItem = 0;
4488 item.iSubItem = 0;
4489 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4490 expect(TRUE, r);
4492 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4494 /* send LVM_EDITLABEL on already created edit */
4495 SetFocus(hwnd);
4496 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4497 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4498 /* focus will be set to edit */
4499 ok(GetFocus() == hwndedit, "Expected Edit window to be focused\n");
4500 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4501 ok(IsWindow(hwndedit2), "Expected Edit window to be created\n");
4503 /* creating label disabled when control isn't focused */
4504 SetFocus(0);
4505 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4506 todo_wine ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4508 /* check EN_KILLFOCUS handling */
4509 memset(&item, 0, sizeof(item));
4510 item.pszText = testitemA;
4511 item.iItem = 0;
4512 item.iSubItem = 0;
4513 r = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
4514 expect(TRUE, r);
4516 SetFocus(hwnd);
4517 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4518 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4519 /* modify edit and notify control that it lost focus */
4520 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem1A);
4521 expect(TRUE, r);
4522 g_editbox_disp_info.item.pszText = NULL;
4523 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4524 expect(0, r);
4525 ok(g_editbox_disp_info.item.pszText != NULL, "expected notification with not null text\n");
4527 memset(&item, 0, sizeof(item));
4528 item.pszText = buffer;
4529 item.cchTextMax = sizeof(buffer);
4530 item.iItem = 0;
4531 item.iSubItem = 0;
4532 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4533 expect(lstrlenA(item.pszText), r);
4534 ok(strcmp(buffer, testitem1A) == 0, "Expected item text to change\n");
4535 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4537 /* change item name to differ in casing only */
4538 SetFocus(hwnd);
4539 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4540 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4541 /* modify edit and notify control that it lost focus */
4542 r = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)testitem2A);
4543 expect(TRUE, r);
4544 g_editbox_disp_info.item.pszText = NULL;
4545 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4546 expect(0, r);
4547 ok(g_editbox_disp_info.item.pszText != NULL, "got %p\n", g_editbox_disp_info.item.pszText);
4549 memset(&item, 0, sizeof(item));
4550 item.pszText = buffer;
4551 item.cchTextMax = sizeof(buffer);
4552 item.iItem = 0;
4553 item.iSubItem = 0;
4554 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4555 expect(lstrlenA(item.pszText), r);
4556 ok(strcmp(buffer, testitem2A) == 0, "got %s, expected %s\n", buffer, testitem2A);
4557 ok(!IsWindow(hwndedit), "Expected Edit window to be freed\n");
4559 /* end edit without saving */
4560 SetFocus(hwnd);
4561 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4562 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4563 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_ESCAPE, 0);
4564 expect(0, r);
4565 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4566 "edit box - end edit, no change, escape", TRUE);
4567 /* end edit with saving */
4568 SetFocus(hwnd);
4569 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4570 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4571 r = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
4572 expect(0, r);
4573 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4574 "edit box - end edit, no change, return", TRUE);
4576 memset(&item, 0, sizeof(item));
4577 item.pszText = buffer;
4578 item.cchTextMax = sizeof(buffer);
4579 item.iItem = 0;
4580 item.iSubItem = 0;
4581 r = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
4582 expect(lstrlenA(item.pszText), r);
4583 ok(strcmp(buffer, testitem2A) == 0, "Expected item text to change\n");
4585 /* LVM_EDITLABEL with -1 destroys current edit */
4586 hwndedit = (HWND)SendMessageA(hwnd, LVM_GETEDITCONTROL, 0, 0);
4587 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4588 /* no edit present */
4589 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4590 ok(hwndedit == NULL, "Expected Edit window not to be created\n");
4591 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4592 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4593 /* edit present */
4594 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4595 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -1, 0);
4596 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4597 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4598 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4599 /* check another negative value */
4600 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4601 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4602 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4603 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, -2, 0);
4604 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4605 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4606 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4607 /* and value greater than max item index */
4608 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4609 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4610 ok(GetFocus() == hwndedit, "Expected Edit to be focused\n");
4611 r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
4612 hwndedit2 = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, r, 0);
4613 ok(hwndedit2 == NULL, "Expected Edit window not to be created\n");
4614 ok(!IsWindow(hwndedit), "Expected Edit window to be destroyed\n");
4615 ok(GetFocus() == hwnd, "Expected List to be focused\n");
4617 /* messaging tests */
4618 SetFocus(hwnd);
4619 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4620 blockEdit = FALSE;
4621 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4622 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4623 /* testing only sizing messages */
4624 ok_sequence(sequences, EDITBOX_SEQ_INDEX, editbox_create_pos,
4625 "edit box create - sizing", FALSE);
4627 /* WM_COMMAND with EN_KILLFOCUS isn't forwarded to parent */
4628 SetFocus(hwnd);
4629 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4630 ok(IsWindow(hwndedit), "Expected Edit window to be created\n");
4631 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4632 r = SendMessageA(hwnd, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hwndedit);
4633 expect(0, r);
4634 ok_sequence(sequences, PARENT_SEQ_INDEX, edit_end_nochange,
4635 "edit box WM_COMMAND (EN_KILLFOCUS)", TRUE);
4637 DestroyWindow(hwnd);
4640 static void test_notifyformat(void)
4642 HWND hwnd, header;
4643 DWORD r;
4645 hwnd = create_listview_control(LVS_REPORT);
4646 ok(hwnd != NULL, "failed to create a listview window\n");
4648 /* CCM_GETUNICODEFORMAT == LVM_GETUNICODEFORMAT,
4649 CCM_SETUNICODEFORMAT == LVM_SETUNICODEFORMAT */
4650 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4651 expect(0, r);
4652 SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4653 /* set */
4654 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 1, 0);
4655 expect(0, r);
4656 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4657 ok(r == 1, "Unexpected return value %ld.\n", r);
4658 r = SendMessageA(hwnd, LVM_SETUNICODEFORMAT, 0, 0);
4659 expect(1, r);
4660 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4661 expect(0, r);
4663 DestroyWindow(hwnd);
4665 /* test failure in parent WM_NOTIFYFORMAT */
4666 notifyFormat = 0;
4667 hwnd = create_listview_control(LVS_REPORT);
4668 ok(hwnd != NULL, "failed to create a listview window\n");
4669 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4670 ok(IsWindow(header), "expected header to be created\n");
4671 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4672 expect(0, r);
4673 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4674 ok( r == 1, "Expected 1, got %ld\n", r );
4675 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_QUERY);
4676 ok(r != 0, "Expected valid format\n");
4678 notifyFormat = NFR_UNICODE;
4679 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4680 expect(NFR_UNICODE, r);
4681 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4682 expect(1, r);
4683 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4684 ok( r == 1, "Expected 1, got %ld\n", r );
4686 notifyFormat = NFR_ANSI;
4687 r = SendMessageA(hwnd, WM_NOTIFYFORMAT, 0, NF_REQUERY);
4688 expect(NFR_ANSI, r);
4689 r = SendMessageA(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4690 expect(0, r);
4691 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4692 ok( r == 1, "Expected 1, got %ld\n", r );
4694 DestroyWindow(hwnd);
4696 hwndparentW = create_parent_window(TRUE);
4697 ok(IsWindow(hwndparentW), "Unicode parent creation failed\n");
4698 if (!IsWindow(hwndparentW)) return;
4700 notifyFormat = -1;
4701 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4702 ok(hwnd != NULL, "failed to create a listview window\n");
4703 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4704 ok(IsWindow(header), "expected header to be created\n");
4705 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4706 expect(1, r);
4707 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4708 expect(1, r);
4709 DestroyWindow(hwnd);
4710 /* receiving error code defaulting to ansi */
4711 notifyFormat = 0;
4712 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4713 ok(hwnd != NULL, "failed to create a listview window\n");
4714 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4715 ok(IsWindow(header), "expected header to be created\n");
4716 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4717 expect(0, r);
4718 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4719 expect(1, r);
4720 DestroyWindow(hwnd);
4721 /* receiving ansi code from unicode window, use it */
4722 notifyFormat = NFR_ANSI;
4723 hwnd = create_listview_controlW(LVS_REPORT, hwndparentW);
4724 ok(hwnd != NULL, "failed to create a listview window\n");
4725 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4726 ok(IsWindow(header), "expected header to be created\n");
4727 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4728 expect(0, r);
4729 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4730 expect(1, r);
4731 DestroyWindow(hwnd);
4732 /* unicode listview with ansi parent window */
4733 notifyFormat = -1;
4734 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4735 ok(hwnd != NULL, "failed to create a listview window\n");
4736 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4737 ok(IsWindow(header), "expected header to be created\n");
4738 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4739 expect(0, r);
4740 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4741 expect(1, r);
4742 DestroyWindow(hwnd);
4743 /* unicode listview with ansi parent window, return error code */
4744 notifyFormat = 0;
4745 hwnd = create_listview_controlW(LVS_REPORT, hwndparent);
4746 ok(hwnd != NULL, "failed to create a listview window\n");
4747 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
4748 ok(IsWindow(header), "expected header to be created\n");
4749 r = SendMessageW(hwnd, LVM_GETUNICODEFORMAT, 0, 0);
4750 expect(0, r);
4751 r = SendMessageA(header, HDM_GETUNICODEFORMAT, 0, 0);
4752 expect(1, r);
4753 DestroyWindow(hwnd);
4755 DestroyWindow(hwndparentW);
4758 static void test_indentation(void)
4760 HWND hwnd;
4761 LVITEMA item;
4762 DWORD r;
4764 hwnd = create_listview_control(LVS_REPORT);
4765 ok(hwnd != NULL, "failed to create a listview window\n");
4767 memset(&item, 0, sizeof(item));
4768 item.mask = LVIF_INDENT;
4769 item.iItem = 0;
4770 item.iIndent = I_INDENTCALLBACK;
4771 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
4772 expect(0, r);
4774 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4776 item.iItem = 0;
4777 item.mask = LVIF_INDENT;
4778 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4779 expect(TRUE, r);
4781 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
4782 "get indent dispinfo", FALSE);
4784 /* Ask for iIndent with invalid subitem. */
4785 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4787 memset(&item, 0, sizeof(item));
4788 item.mask = LVIF_INDENT;
4789 item.iSubItem = 1;
4790 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
4791 ok(r, "Failed to get item.\n");
4793 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "get indent dispinfo 2", FALSE);
4795 DestroyWindow(hwnd);
4798 static void test_get_set_view(void)
4800 HWND hwnd;
4801 DWORD ret;
4802 DWORD_PTR style;
4804 /* test style->view mapping */
4805 hwnd = create_listview_control(LVS_REPORT);
4806 ok(hwnd != NULL, "failed to create a listview window\n");
4808 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4809 expect(LV_VIEW_DETAILS, ret);
4811 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4812 /* LVS_ICON == 0 */
4813 SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_REPORT);
4814 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4815 expect(LV_VIEW_ICON, ret);
4817 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4818 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SMALLICON);
4819 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4820 expect(LV_VIEW_SMALLICON, ret);
4822 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4823 SetWindowLongPtrA(hwnd, GWL_STYLE, (style & ~LVS_SMALLICON) | LVS_LIST);
4824 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4825 expect(LV_VIEW_LIST, ret);
4827 /* switching view doesn't touch window style */
4828 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_DETAILS, 0);
4829 expect(1, ret);
4830 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4831 ok(style & LVS_LIST, "Expected style to be preserved\n");
4832 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_ICON, 0);
4833 expect(1, ret);
4834 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4835 ok(style & LVS_LIST, "Expected style to be preserved\n");
4836 ret = SendMessageA(hwnd, LVM_SETVIEW, LV_VIEW_SMALLICON, 0);
4837 expect(1, ret);
4838 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4839 ok(style & LVS_LIST, "Expected style to be preserved\n");
4841 /* now change window style to see if view is remapped */
4842 style = GetWindowLongPtrA(hwnd, GWL_STYLE);
4843 SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS);
4844 ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0);
4845 expect(LV_VIEW_SMALLICON, ret);
4847 DestroyWindow(hwnd);
4850 static void test_canceleditlabel(void)
4852 HWND hwnd, hwndedit;
4853 DWORD ret;
4854 CHAR buff[10];
4855 LVITEMA itema;
4856 static CHAR test[] = "test";
4857 static const CHAR test1[] = "test1";
4859 hwnd = create_listview_control(LVS_EDITLABELS | LVS_REPORT);
4860 ok(hwnd != NULL, "failed to create a listview window\n");
4862 insert_item(hwnd, 0);
4864 /* try without edit created */
4865 flush_sequences(sequences, NUM_MSG_SEQUENCES);
4866 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4867 expect(TRUE, ret);
4868 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
4869 "cancel edit label without edit", FALSE);
4871 /* cancel without data change */
4872 SetFocus(hwnd);
4873 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4874 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4875 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4876 expect(TRUE, ret);
4877 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4879 /* cancel after data change */
4880 memset(&itema, 0, sizeof(itema));
4881 itema.pszText = test;
4882 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
4883 expect(TRUE, ret);
4884 SetFocus(hwnd);
4885 hwndedit = (HWND)SendMessageA(hwnd, LVM_EDITLABELA, 0, 0);
4886 ok(IsWindow(hwndedit), "Expected edit control to be created\n");
4887 ret = SetWindowTextA(hwndedit, test1);
4888 expect(1, ret);
4889 ret = SendMessageA(hwnd, LVM_CANCELEDITLABEL, 0, 0);
4890 expect(TRUE, ret);
4891 ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
4892 memset(&itema, 0, sizeof(itema));
4893 itema.pszText = buff;
4894 itema.cchTextMax = ARRAY_SIZE(buff);
4895 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
4896 expect(5, ret);
4897 ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
4899 DestroyWindow(hwnd);
4902 static void test_mapidindex(void)
4904 HWND hwnd;
4905 INT ret;
4907 /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
4908 hwnd = create_listview_control(LVS_OWNERDATA | LVS_REPORT);
4909 ok(hwnd != NULL, "failed to create a listview window\n");
4910 insert_item(hwnd, 0);
4911 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4912 expect(-1, ret);
4913 DestroyWindow(hwnd);
4915 hwnd = create_listview_control(LVS_REPORT);
4916 ok(hwnd != NULL, "failed to create a listview window\n");
4918 /* LVM_MAPINDEXTOID with invalid index */
4919 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4920 expect(-1, ret);
4922 insert_item(hwnd, 0);
4923 insert_item(hwnd, 1);
4925 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, -1, 0);
4926 expect(-1, ret);
4927 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 2, 0);
4928 expect(-1, ret);
4930 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4931 expect(0, ret);
4932 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4933 expect(1, ret);
4934 /* remove 0 indexed item, id retained */
4935 SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
4936 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 0, 0);
4937 expect(1, ret);
4938 /* new id starts from previous value */
4939 insert_item(hwnd, 1);
4940 ret = SendMessageA(hwnd, LVM_MAPINDEXTOID, 1, 0);
4941 expect(2, ret);
4943 /* get index by id */
4944 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, -1, 0);
4945 expect(-1, ret);
4946 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 0, 0);
4947 expect(-1, ret);
4948 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 1, 0);
4949 expect(0, ret);
4950 ret = SendMessageA(hwnd, LVM_MAPIDTOINDEX, 2, 0);
4951 expect(1, ret);
4953 DestroyWindow(hwnd);
4956 static void test_getitemspacing(void)
4958 HWND hwnd;
4959 DWORD ret;
4960 INT cx, cy;
4961 HIMAGELIST himl40, himl80;
4963 cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON);
4964 cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
4966 /* LVS_ICON */
4967 hwnd = create_listview_control(LVS_ICON);
4968 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4969 expect(cx, LOWORD(ret));
4970 expect(cy, HIWORD(ret));
4972 /* now try with icons */
4973 himl40 = pImageList_Create(40, 40, 0, 4, 4);
4974 ok(himl40 != NULL, "failed to create imagelist\n");
4975 himl80 = pImageList_Create(80, 80, 0, 4, 4);
4976 ok(himl80 != NULL, "failed to create imagelist\n");
4977 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
4978 expect(0, ret);
4980 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4981 /* spacing + icon size returned */
4982 expect(cx + 40, LOWORD(ret));
4983 expect(cy + 40, HIWORD(ret));
4984 /* try changing icon size */
4985 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl80);
4987 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4988 /* spacing + icon size returned */
4989 expect(cx + 80, LOWORD(ret));
4990 expect(cy + 80, HIWORD(ret));
4992 /* set own icon spacing */
4993 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(100, 100));
4994 expect(cx + 80, LOWORD(ret));
4995 expect(cy + 80, HIWORD(ret));
4997 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
4998 /* set size returned */
4999 expect(100, LOWORD(ret));
5000 expect(100, HIWORD(ret));
5002 /* now change image list - icon spacing should be unaffected */
5003 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
5005 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5006 /* set size returned */
5007 expect(100, LOWORD(ret));
5008 expect(100, HIWORD(ret));
5010 /* spacing = 0 - keep previous value */
5011 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(0, -1));
5012 expect(100, LOWORD(ret));
5013 expect(100, HIWORD(ret));
5015 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5016 expect(100, LOWORD(ret));
5018 expect(0xFFFF, HIWORD(ret));
5020 if (sizeof(void*) == 8)
5022 /* NOTE: -1 is not treated the same as (DWORD)-1 by 64bit listview */
5023 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, (DWORD)-1);
5024 expect(100, LOWORD(ret));
5025 expect(0xFFFF, HIWORD(ret));
5027 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
5028 expect(0xFFFF, LOWORD(ret));
5029 expect(0xFFFF, HIWORD(ret));
5031 else
5033 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, -1);
5034 expect(100, LOWORD(ret));
5035 expect(0xFFFF, HIWORD(ret));
5037 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5038 /* spacing + icon size returned */
5039 expect(cx + 40, LOWORD(ret));
5040 expect(cy + 40, HIWORD(ret));
5042 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
5043 pImageList_Destroy(himl80);
5044 DestroyWindow(hwnd);
5045 /* LVS_SMALLICON */
5046 hwnd = create_listview_control(LVS_SMALLICON);
5047 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5048 expect(cx, LOWORD(ret));
5049 expect(cy, HIWORD(ret));
5051 /* spacing does not depend on selected view type */
5052 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl40);
5053 expect(0, ret);
5055 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5056 /* spacing + icon size returned */
5057 expect(cx + 40, LOWORD(ret));
5058 expect(cy + 40, HIWORD(ret));
5060 SendMessageA(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
5061 pImageList_Destroy(himl40);
5062 DestroyWindow(hwnd);
5063 /* LVS_REPORT */
5064 hwnd = create_listview_control(LVS_REPORT);
5065 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5066 expect(cx, LOWORD(ret));
5067 expect(cy, HIWORD(ret));
5069 DestroyWindow(hwnd);
5070 /* LVS_LIST */
5071 hwnd = create_listview_control(LVS_LIST);
5072 ret = SendMessageA(hwnd, LVM_GETITEMSPACING, FALSE, 0);
5073 expect(cx, LOWORD(ret));
5074 expect(cy, HIWORD(ret));
5076 DestroyWindow(hwnd);
5079 static INT get_current_font_height(HWND listview)
5081 TEXTMETRICA tm;
5082 HFONT hfont;
5083 HWND hwnd;
5084 HDC hdc;
5086 hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0);
5087 if (!hwnd)
5088 hwnd = listview;
5090 hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0);
5091 if (!hfont) {
5092 hdc = GetDC(hwnd);
5093 GetTextMetricsA(hdc, &tm);
5094 ReleaseDC(hwnd, hdc);
5096 else {
5097 HFONT oldfont;
5099 hdc = GetDC(0);
5100 oldfont = SelectObject(hdc, hfont);
5101 GetTextMetricsA(hdc, &tm);
5102 SelectObject(hdc, oldfont);
5103 ReleaseDC(0, hdc);
5106 return tm.tmHeight;
5109 static void test_getcolumnwidth(void)
5111 HWND hwnd;
5112 INT ret;
5113 DWORD_PTR style;
5114 LVCOLUMNA col;
5115 LVITEMA itema;
5116 INT height;
5118 /* default column width */
5119 hwnd = create_listview_control(LVS_ICON);
5120 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5121 expect(0, ret);
5122 style = GetWindowLongA(hwnd, GWL_STYLE);
5123 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_LIST);
5124 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5125 todo_wine expect(8, ret);
5126 style = GetWindowLongA(hwnd, GWL_STYLE) & ~LVS_LIST;
5127 SetWindowLongA(hwnd, GWL_STYLE, style | LVS_REPORT);
5128 col.mask = 0;
5129 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5130 expect(0, ret);
5131 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5132 expect(10, ret);
5133 DestroyWindow(hwnd);
5135 /* default column width with item added */
5136 hwnd = create_listview_control(LVS_LIST);
5137 memset(&itema, 0, sizeof(itema));
5138 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5139 ok(!ret, "got %d\n", ret);
5140 ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
5141 height = get_current_font_height(hwnd);
5142 ok((ret / height) >= 6, "got width %d, height %d\n", ret, height);
5143 DestroyWindow(hwnd);
5146 static void test_scrollnotify(void)
5148 HWND hwnd;
5149 DWORD ret;
5151 hwnd = create_listview_control(LVS_REPORT);
5153 insert_column(hwnd, 0);
5154 insert_column(hwnd, 1);
5155 insert_item(hwnd, 0);
5157 /* make it scrollable - resize */
5158 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(100, 0));
5159 expect(TRUE, ret);
5160 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(100, 0));
5161 expect(TRUE, ret);
5163 /* try with dummy call */
5164 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5165 ret = SendMessageA(hwnd, LVM_SCROLL, 0, 0);
5166 expect(TRUE, ret);
5167 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
5168 "scroll notify 1", TRUE);
5170 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5171 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 0);
5172 expect(TRUE, ret);
5173 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
5174 "scroll notify 2", TRUE);
5176 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5177 ret = SendMessageA(hwnd, LVM_SCROLL, 1, 1);
5178 expect(TRUE, ret);
5179 ok_sequence(sequences, PARENT_SEQ_INDEX, scroll_parent_seq,
5180 "scroll notify 3", TRUE);
5182 DestroyWindow(hwnd);
5185 static void test_LVS_EX_TRANSPARENTBKGND(void)
5187 HWND hwnd;
5188 DWORD ret;
5189 HDC hdc;
5191 hwnd = create_listview_control(LVS_REPORT);
5193 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5194 expect(TRUE, ret);
5196 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5197 LVS_EX_TRANSPARENTBKGND);
5199 ret = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
5200 if (ret != CLR_NONE)
5202 win_skip("LVS_EX_TRANSPARENTBKGND unsupported\n");
5203 DestroyWindow(hwnd);
5204 return;
5207 /* try to set some back color and check this style bit */
5208 ret = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, RGB(0, 0, 0));
5209 expect(TRUE, ret);
5210 ret = SendMessageA(hwnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
5211 ok(!(ret & LVS_EX_TRANSPARENTBKGND), "Expected LVS_EX_TRANSPARENTBKGND to unset\n");
5213 /* now test what this style actually does */
5214 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTBKGND,
5215 LVS_EX_TRANSPARENTBKGND);
5217 hdc = GetWindowDC(hwndparent);
5219 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5220 SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
5221 ok_sequence(sequences, PARENT_SEQ_INDEX, lvs_ex_transparentbkgnd_seq,
5222 "LVS_EX_TRANSPARENTBKGND parent", FALSE);
5224 ReleaseDC(hwndparent, hdc);
5226 DestroyWindow(hwnd);
5229 static void test_approximate_viewrect(void)
5231 static CHAR test[] = "abracadabra, a very long item label";
5232 DWORD item_width, item_height, header_height;
5233 static CHAR column_header[] = "Header";
5234 unsigned const column_width = 100;
5235 DWORD ret, item_count;
5236 HIMAGELIST himl;
5237 LVITEMA itema;
5238 LVCOLUMNA col;
5239 HBITMAP hbmp;
5240 HWND hwnd;
5242 /* LVS_ICON */
5243 hwnd = create_listview_control(LVS_ICON);
5244 himl = pImageList_Create(40, 40, 0, 4, 4);
5245 ok(himl != NULL, "failed to create imagelist\n");
5246 hbmp = CreateBitmap(40, 40, 1, 1, NULL);
5247 ok(hbmp != NULL, "failed to create bitmap\n");
5248 ret = pImageList_Add(himl, hbmp, 0);
5249 expect(0, ret);
5250 ret = SendMessageA(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
5251 expect(0, ret);
5253 itema.mask = LVIF_IMAGE;
5254 itema.iImage = 0;
5255 itema.iItem = 0;
5256 itema.iSubItem = 0;
5257 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5258 expect(0, ret);
5260 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(75, 75));
5261 ok(ret != 0, "Unexpected return value %#lx.\n", ret);
5263 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5264 expect(MAKELONG(77,827), ret);
5266 ret = SendMessageA(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(50, 50));
5267 ok(ret != 0, "got 0\n");
5269 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 11, MAKELPARAM(100,100));
5270 expect(MAKELONG(102,302), ret);
5272 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5273 expect(MAKELONG(52,52), ret);
5275 itema.pszText = test;
5276 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&itema);
5277 expect(TRUE, ret);
5278 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, MAKELPARAM(100,100));
5279 expect(MAKELONG(52,52), ret);
5281 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100,100));
5282 expect(MAKELONG(52,2), ret);
5283 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, MAKELPARAM(100,100));
5284 expect(MAKELONG(52,52), ret);
5285 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELPARAM(100,100));
5286 expect(MAKELONG(102,52), ret);
5287 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 3, MAKELPARAM(100,100));
5288 expect(MAKELONG(102,102), ret);
5289 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 4, MAKELPARAM(100,100));
5290 expect(MAKELONG(102,102), ret);
5291 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 5, MAKELPARAM(100,100));
5292 expect(MAKELONG(102,152), ret);
5293 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 6, MAKELPARAM(100,100));
5294 expect(MAKELONG(102,152), ret);
5295 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 7, MAKELPARAM(160,100));
5296 expect(MAKELONG(152,152), ret);
5298 DestroyWindow(hwnd);
5300 /* LVS_REPORT */
5301 hwnd = create_listview_control(LVS_REPORT);
5303 /* Empty control without columns */
5304 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, MAKELPARAM(100, 100));
5305 todo_wine
5306 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5307 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5309 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5310 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5311 todo_wine
5312 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5314 header_height = HIWORD(ret);
5316 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5317 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5318 todo_wine
5319 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5321 item_height = HIWORD(ret) - header_height;
5323 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5324 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5325 ok(HIWORD(ret) == (header_height - 2 * item_height), "Unexpected height %d.\n", HIWORD(ret)) ;
5327 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5328 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5329 ok(HIWORD(ret) == header_height, "Unexpected height.\n");
5330 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5331 ok(LOWORD(ret) == 0, "Unexpected width %d.\n", LOWORD(ret));
5332 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5334 /* Insert column */
5335 col.mask = LVCF_TEXT | LVCF_WIDTH;
5336 col.pszText = column_header;
5337 col.cx = column_width;
5338 ret = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5339 ok(ret == 0, "Unexpected return value %ld.\n", ret);
5341 /* Empty control with column */
5342 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5343 todo_wine {
5344 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5345 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5347 header_height = HIWORD(ret);
5348 item_width = LOWORD(ret);
5350 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5351 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5352 todo_wine
5353 ok(HIWORD(ret) > header_height, "Unexpected height %d.\n", HIWORD(ret));
5355 item_height = HIWORD(ret) - header_height;
5357 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5358 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5359 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5361 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5362 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5363 ok(HIWORD(ret) == header_height, "Unexpected height %d.\n", HIWORD(ret));
5365 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5366 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5367 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5369 for (item_count = 1; item_count <= 2; ++item_count)
5371 itema.mask = LVIF_TEXT;
5372 itema.iItem = 0;
5373 itema.iSubItem = 0;
5374 itema.pszText = test;
5375 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema);
5376 ok(ret == 0, "Unexpected return value %ld.\n", ret);
5378 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 0, 0);
5379 ok(LOWORD(ret) >= column_width, "Unexpected width %d.\n", LOWORD(ret));
5380 todo_wine
5381 ok(HIWORD(ret) != 0, "Unexpected height %d.\n", HIWORD(ret));
5383 header_height = HIWORD(ret);
5384 item_width = LOWORD(ret);
5386 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 1, 0);
5387 ok(LOWORD(ret) == item_width, "Unexpected width %d, item %ld\n", LOWORD(ret), item_count - 1);
5388 ok(HIWORD(ret) > header_height, "Unexpected height %d. item %ld.\n", HIWORD(ret), item_count - 1);
5390 item_height = HIWORD(ret) - header_height;
5392 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, 0);
5393 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5394 todo_wine
5395 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5397 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -1, 0);
5398 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5399 ok(HIWORD(ret) == header_height + item_count * item_height, "Unexpected height %d.\n", HIWORD(ret));
5401 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, 0);
5402 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5403 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5405 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, 2, MAKELONG(item_width * 2, header_height + 3 * item_height));
5406 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5407 ok(HIWORD(ret) == header_height + 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5409 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(item_width * 2, 0));
5410 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5411 todo_wine
5412 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5414 ret = SendMessageA(hwnd, LVM_APPROXIMATEVIEWRECT, -2, MAKELONG(-1, -1));
5415 ok(LOWORD(ret) == item_width, "Unexpected width %d.\n", LOWORD(ret));
5416 todo_wine
5417 ok(HIWORD(ret) == header_height - 2 * item_height, "Unexpected height %d.\n", HIWORD(ret));
5420 DestroyWindow(hwnd);
5424 static void test_finditem(void)
5426 LVFINDINFOA fi;
5427 static char f[5];
5428 HWND hwnd;
5429 INT r;
5431 hwnd = create_listview_control(LVS_REPORT);
5432 insert_item(hwnd, 0);
5434 memset(&fi, 0, sizeof(fi));
5436 /* full string search, inserted text was "foo" */
5437 strcpy(f, "foo");
5438 fi.flags = LVFI_STRING;
5439 fi.psz = f;
5440 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5441 expect(0, r);
5443 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5444 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5445 expect(0, r);
5447 fi.flags = LVFI_PARTIAL;
5448 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5449 expect(0, r);
5451 /* partial string search, inserted text was "foo" */
5452 strcpy(f, "fo");
5453 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5454 fi.psz = f;
5455 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5456 expect(0, r);
5458 fi.flags = LVFI_STRING;
5459 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5460 expect(-1, r);
5462 fi.flags = LVFI_PARTIAL;
5463 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5464 expect(0, r);
5466 /* partial string search, part after start char */
5467 strcpy(f, "oo");
5468 fi.flags = LVFI_STRING | LVFI_PARTIAL;
5469 fi.psz = f;
5470 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5471 expect(-1, r);
5473 /* try with LVFI_SUBSTRING */
5474 strcpy(f, "fo");
5475 fi.flags = LVFI_SUBSTRING;
5476 fi.psz = f;
5477 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5478 expect(0, r);
5479 strcpy(f, "f");
5480 fi.flags = LVFI_SUBSTRING;
5481 fi.psz = f;
5482 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5483 expect(0, r);
5484 strcpy(f, "o");
5485 fi.flags = LVFI_SUBSTRING;
5486 fi.psz = f;
5487 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5488 expect(-1, r);
5490 strcpy(f, "o");
5491 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5492 fi.psz = f;
5493 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5494 expect(-1, r);
5496 strcpy(f, "f");
5497 fi.flags = LVFI_SUBSTRING | LVFI_STRING;
5498 fi.psz = f;
5499 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5500 expect(0, r);
5502 fi.flags = LVFI_SUBSTRING | LVFI_PARTIAL;
5503 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5504 expect(0, r);
5506 /* Case sensitivity. */
5507 strcpy(f, "Foo");
5508 fi.flags = LVFI_STRING;
5509 fi.psz = f;
5510 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5511 ok(!r, "Unexpected item index %d.\n", r);
5513 strcpy(f, "F");
5514 fi.flags = LVFI_SUBSTRING;
5515 fi.psz = f;
5516 r = SendMessageA(hwnd, LVM_FINDITEMA, -1, (LPARAM)&fi);
5517 ok(!r, "Unexpected item index %d.\n", r);
5519 DestroyWindow(hwnd);
5522 static void test_LVS_EX_HEADERINALLVIEWS(void)
5524 HWND hwnd, header;
5525 DWORD style;
5527 hwnd = create_listview_control(LVS_ICON);
5529 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5530 LVS_EX_HEADERINALLVIEWS);
5532 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5533 if (!IsWindow(header))
5535 win_skip("LVS_EX_HEADERINALLVIEWS unsupported\n");
5536 DestroyWindow(hwnd);
5537 return;
5540 /* LVS_NOCOLUMNHEADER works as before */
5541 style = GetWindowLongA(hwnd, GWL_STYLE);
5542 SetWindowLongW(hwnd, GWL_STYLE, style | LVS_NOCOLUMNHEADER);
5543 style = GetWindowLongA(header, GWL_STYLE);
5544 ok(style & HDS_HIDDEN, "Expected HDS_HIDDEN\n");
5545 style = GetWindowLongA(hwnd, GWL_STYLE);
5546 SetWindowLongW(hwnd, GWL_STYLE, style & ~LVS_NOCOLUMNHEADER);
5547 style = GetWindowLongA(header, GWL_STYLE);
5548 ok(!(style & HDS_HIDDEN), "Expected HDS_HIDDEN to be unset\n");
5550 /* try to remove style */
5551 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, 0);
5552 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5553 ok(IsWindow(header), "Expected header to be created\n");
5554 style = GetWindowLongA(header, GWL_STYLE);
5555 ok(!(style & HDS_HIDDEN), "HDS_HIDDEN not expected\n");
5557 DestroyWindow(hwnd);
5559 /* check other styles */
5560 hwnd = create_listview_control(LVS_LIST);
5561 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5562 LVS_EX_HEADERINALLVIEWS);
5563 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5564 ok(IsWindow(header), "Expected header to be created\n");
5565 DestroyWindow(hwnd);
5567 hwnd = create_listview_control(LVS_SMALLICON);
5568 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5569 LVS_EX_HEADERINALLVIEWS);
5570 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5571 ok(IsWindow(header), "Expected header to be created\n");
5572 DestroyWindow(hwnd);
5574 hwnd = create_listview_control(LVS_REPORT);
5575 SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS,
5576 LVS_EX_HEADERINALLVIEWS);
5577 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
5578 ok(IsWindow(header), "Expected header to be created\n");
5579 DestroyWindow(hwnd);
5582 static void test_hover(void)
5584 HWND hwnd, fg;
5585 DWORD r;
5587 hwnd = create_listview_control(LVS_ICON);
5588 SetForegroundWindow(hwndparent);
5589 fg = GetForegroundWindow();
5590 if (fg != hwndparent)
5592 skip("Window is not in the foreground. Skipping hover tests.\n");
5593 DestroyWindow(hwnd);
5594 return;
5597 /* test WM_MOUSEHOVER forwarding */
5598 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5599 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5600 expect(0, r);
5601 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER allow test", TRUE);
5602 g_block_hover = TRUE;
5603 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5604 r = SendMessageA(hwnd, WM_MOUSEHOVER, 0, 0);
5605 expect(0, r);
5606 ok_sequence(sequences, PARENT_SEQ_INDEX, hover_parent, "NM_HOVER block test", TRUE);
5607 g_block_hover = FALSE;
5609 r = SendMessageA(hwnd, LVM_SETHOVERTIME, 0, 500);
5610 expect(HOVER_DEFAULT, r);
5611 r = SendMessageA(hwnd, LVM_GETHOVERTIME, 0, 0);
5612 expect(500, r);
5614 DestroyWindow(hwnd);
5617 static void test_destroynotify(void)
5619 HWND hwnd;
5620 BOOL ret;
5622 hwnd = create_listview_control(LVS_REPORT);
5623 ok(hwnd != NULL, "failed to create listview window\n");
5625 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5626 DestroyWindow(hwnd);
5627 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_destroy, "check destroy order", FALSE);
5629 /* same for ownerdata list */
5630 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5631 ok(hwnd != NULL, "failed to create listview window\n");
5633 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5634 DestroyWindow(hwnd);
5635 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_destroy, "check destroy order, ownerdata", FALSE);
5637 hwnd = create_listview_control(LVS_REPORT|LVS_OWNERDATA);
5638 ok(hwnd != NULL, "failed to create listview window\n");
5640 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5641 ret = SendMessageA(hwnd, LVM_DELETEALLITEMS, 0, 0);
5642 ok(ret == TRUE, "got %d\n", ret);
5643 ok_sequence(sequences, COMBINED_SEQ_INDEX, listview_ownerdata_deleteall, "deleteall ownerdata", FALSE);
5644 DestroyWindow(hwnd);
5647 static void test_header_notification(void)
5649 static char textA[] = "newtext";
5650 HWND list, header;
5651 HDITEMA item;
5652 NMHEADERA nmh;
5653 LVCOLUMNA col;
5654 DWORD ret;
5655 BOOL r;
5657 list = create_listview_control(LVS_REPORT);
5658 ok(list != NULL, "failed to create listview window\n");
5660 memset(&col, 0, sizeof(col));
5661 col.mask = LVCF_WIDTH;
5662 col.cx = 100;
5663 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5664 expect(0, ret);
5666 /* check list parent notification after header item changed,
5667 this test should be placed before header subclassing to avoid
5668 Listview -> Header messages to be logged */
5669 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5671 col.mask = LVCF_TEXT;
5672 col.pszText = textA;
5673 r = SendMessageA(list, LVM_SETCOLUMNA, 0, (LPARAM)&col);
5674 expect(TRUE, r);
5676 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_changed_seq,
5677 "header notify, listview", FALSE);
5678 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5679 "header notify, parent", FALSE);
5681 header = subclass_header(list);
5683 ret = SendMessageA(header, HDM_GETITEMCOUNT, 0, 0);
5684 expect(1, ret);
5686 memset(&item, 0, sizeof(item));
5687 item.mask = HDI_WIDTH;
5688 ret = SendMessageA(header, HDM_GETITEMA, 0, (LPARAM)&item);
5689 expect(1, ret);
5690 expect(100, item.cxy);
5692 nmh.hdr.hwndFrom = header;
5693 nmh.hdr.idFrom = GetWindowLongPtrA(header, GWLP_ID);
5694 nmh.hdr.code = HDN_ITEMCHANGEDA;
5695 nmh.iItem = 0;
5696 nmh.iButton = 0;
5697 item.mask = HDI_WIDTH;
5698 item.cxy = 50;
5699 nmh.pitem = &item;
5700 ret = SendMessageA(list, WM_NOTIFY, 0, (LPARAM)&nmh);
5701 expect(0, ret);
5703 DestroyWindow(list);
5706 static void test_header_notification2(void)
5708 static char textA[] = "newtext";
5709 HWND list, header;
5710 HDITEMW itemW;
5711 NMHEADERW nmhdr;
5712 LVCOLUMNA col;
5713 DWORD ret;
5714 WCHAR buffer[100];
5715 struct message parent_header_notify_seq[] = {
5716 { WM_NOTIFY, sent|id, 0, 0, 0 },
5717 { 0 }
5720 list = create_listview_control(LVS_REPORT);
5721 ok(list != NULL, "failed to create listview window\n");
5723 memset(&col, 0, sizeof(col));
5724 col.mask = LVCF_WIDTH | LVCF_TEXT;
5725 col.cx = 100;
5726 col.pszText = textA;
5727 ret = SendMessageA(list, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
5728 expect(0, ret);
5730 header = (HWND)SendMessageA(list, LVM_GETHEADER, 0, 0);
5731 ok(header != 0, "No header\n");
5732 memset(&itemW, 0, sizeof(itemW));
5733 itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
5734 itemW.pszText = buffer;
5735 itemW.cchTextMax = ARRAY_SIZE(buffer);
5736 ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
5737 expect(1, ret);
5739 nmhdr.hdr.hwndFrom = header;
5740 nmhdr.hdr.idFrom = GetWindowLongPtrW(header, GWLP_ID);
5741 nmhdr.iItem = 0;
5742 nmhdr.iButton = 0;
5743 nmhdr.pitem = &itemW;
5745 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5746 nmhdr.hdr.code = HDN_ITEMCHANGINGW;
5747 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5748 ok(ret == 0, "got %ld\n", ret);
5749 parent_header_notify_seq[0].id = HDN_ITEMCHANGINGA;
5750 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5751 "header notify, parent", TRUE);
5752 todo_wine
5753 ok(nmhdr.hdr.code == HDN_ITEMCHANGINGA, "Expected ANSI notification code\n");
5754 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5755 nmhdr.hdr.code = HDN_ITEMCHANGEDW;
5756 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5757 ok(ret == 0, "got %ld\n", ret);
5758 parent_header_notify_seq[0].id = HDN_ITEMCHANGEDA;
5759 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5760 "header notify, parent", TRUE);
5761 todo_wine
5762 ok(nmhdr.hdr.code == HDN_ITEMCHANGEDA, "Expected ANSI notification code\n");
5763 /* HDN_ITEMCLICK sets focus to list, which generates messages we don't want to check */
5764 SetFocus(list);
5765 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5766 nmhdr.hdr.code = HDN_ITEMCLICKW;
5767 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5768 ok(ret == 0, "got %ld\n", ret);
5769 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_click_seq,
5770 "header notify, parent", FALSE);
5771 ok(nmhdr.hdr.code == HDN_ITEMCLICKA, "Expected ANSI notification code\n");
5772 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5773 nmhdr.hdr.code = HDN_ITEMDBLCLICKW;
5774 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5775 ok(ret == 0, "got %ld\n", ret);
5776 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5777 "header notify, parent", FALSE);
5778 ok(nmhdr.hdr.code == HDN_ITEMDBLCLICKW, "Expected Unicode notification code\n");
5779 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5780 nmhdr.hdr.code = HDN_DIVIDERDBLCLICKW;
5781 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5782 ok(ret == 0, "got %ld\n", ret);
5783 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_divider_dclick_seq,
5784 "header notify, parent", TRUE);
5785 ok(nmhdr.hdr.code == HDN_DIVIDERDBLCLICKA, "Expected ANSI notification code\n");
5786 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5787 nmhdr.hdr.code = HDN_BEGINTRACKW;
5788 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5789 ok(ret == 0, "got %ld\n", ret);
5790 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5791 "header notify, parent", FALSE);
5792 ok(nmhdr.hdr.code == HDN_BEGINTRACKW, "Expected Unicode notification code\n");
5793 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5794 nmhdr.hdr.code = HDN_ENDTRACKW;
5795 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5796 ok(ret == 0, "got %ld\n", ret);
5797 parent_header_notify_seq[0].id = HDN_ENDTRACKA;
5798 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5799 "header notify, parent", FALSE);
5800 ok(nmhdr.hdr.code == HDN_ENDTRACKA, "Expected ANSI notification code\n");
5801 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5802 nmhdr.hdr.code = HDN_TRACKW;
5803 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5804 ok(ret == 0, "got %ld\n", ret);
5805 parent_header_notify_seq[0].id = HDN_TRACKA;
5806 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5807 "header notify, parent", FALSE);
5808 ok(nmhdr.hdr.code == HDN_TRACKA, "Expected ANSI notification code\n");
5809 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5810 nmhdr.hdr.code = HDN_BEGINDRAG;
5811 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5812 ok(ret == 1, "got %ld\n", ret);
5813 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5814 "header notify, parent", FALSE);
5815 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5816 nmhdr.hdr.code = HDN_ENDDRAG;
5817 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5818 ok(ret == 0, "got %ld\n", ret);
5819 parent_header_notify_seq[0].id = HDN_ENDDRAG;
5820 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5821 "header notify, parent", FALSE);
5822 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5823 nmhdr.hdr.code = HDN_FILTERCHANGE;
5824 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5825 ok(ret == 0, "got %ld\n", ret);
5826 parent_header_notify_seq[0].id = HDN_FILTERCHANGE;
5827 parent_header_notify_seq[0].flags |= optional; /* NT4 does not send this message */
5828 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_header_notify_seq,
5829 "header notify, parent", FALSE);
5830 parent_header_notify_seq[0].flags &= ~optional;
5831 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5832 nmhdr.hdr.code = HDN_BEGINFILTEREDIT;
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_ENDFILTEREDIT;
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_ITEMSTATEICONCLICK;
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);
5849 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5850 nmhdr.hdr.code = HDN_ITEMKEYDOWN;
5851 ret = SendMessageW(list, WM_NOTIFY, 0, (LPARAM)&nmhdr);
5852 ok(ret == 0, "got %ld\n", ret);
5853 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
5854 "header notify, parent", FALSE);
5856 flush_sequences(sequences, NUM_MSG_SEQUENCES);
5858 DestroyWindow(list);
5861 static void test_createdragimage(void)
5863 HIMAGELIST himl;
5864 POINT pt;
5865 HWND list;
5867 list = create_listview_control(LVS_ICON);
5868 ok(list != NULL, "failed to create listview window\n");
5870 insert_item(list, 0);
5872 /* NULL point */
5873 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, 0);
5874 ok(himl == NULL, "got %p\n", himl);
5876 himl = (HIMAGELIST)SendMessageA(list, LVM_CREATEDRAGIMAGE, 0, (LPARAM)&pt);
5877 ok(himl != NULL, "got %p\n", himl);
5878 pImageList_Destroy(himl);
5880 DestroyWindow(list);
5883 static void test_dispinfo(void)
5885 static const char testA[] = "TEST";
5886 WCHAR buff[10];
5887 LVITEMA item;
5888 HWND hwnd;
5889 DWORD ret;
5891 hwnd = create_listview_control(LVS_ICON);
5892 ok(hwnd != NULL, "failed to create listview window\n");
5894 insert_item(hwnd, 0);
5896 memset(&item, 0, sizeof(item));
5897 item.pszText = LPSTR_TEXTCALLBACKA;
5898 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5899 expect(1, ret);
5901 g_disp_A_to_W = TRUE;
5902 item.pszText = (char*)buff;
5903 item.cchTextMax = ARRAY_SIZE(buff);
5904 ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
5905 ok(ret == sizeof(testA)-1, "got %ld, expected 4\n", ret);
5906 g_disp_A_to_W = FALSE;
5908 ok(memcmp(item.pszText, testA, sizeof(testA)) == 0,
5909 "got %s, expected %s\n", item.pszText, testA);
5911 DestroyWindow(hwnd);
5914 static void test_LVM_SETITEMTEXT(void)
5916 static char testA[] = "TEST";
5917 LVITEMA item;
5918 HWND hwnd;
5919 DWORD ret;
5921 hwnd = create_listview_control(LVS_ICON);
5922 ok(hwnd != NULL, "failed to create listview window\n");
5924 insert_item(hwnd, 0);
5926 /* null item pointer */
5927 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, 0);
5928 expect(FALSE, ret);
5930 ret = SendMessageA(hwnd, LVM_SETITEMTEXTW, 0, 0);
5931 expect(FALSE, ret);
5933 /* index out of bounds */
5934 item.pszText = testA;
5935 item.cchTextMax = 0; /* ignored */
5936 item.iSubItem = 0;
5938 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 1, (LPARAM)&item);
5939 expect(FALSE, ret);
5941 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, -1, (LPARAM)&item);
5942 expect(FALSE, ret);
5944 ret = SendMessageA(hwnd, LVM_SETITEMTEXTA, 0, (LPARAM)&item);
5945 expect(TRUE, ret);
5947 DestroyWindow(hwnd);
5950 static void test_LVM_REDRAWITEMS(void)
5952 HWND list;
5953 DWORD ret;
5955 list = create_listview_control(LVS_ICON);
5956 ok(list != NULL, "failed to create listview window\n");
5958 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5959 expect(TRUE, ret);
5961 insert_item(list, 0);
5963 ret = SendMessageA(list, LVM_REDRAWITEMS, -1, 0);
5964 expect(TRUE, ret);
5966 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, -1);
5967 expect(TRUE, ret);
5969 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 0);
5970 expect(TRUE, ret);
5972 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 1);
5973 expect(TRUE, ret);
5975 ret = SendMessageA(list, LVM_REDRAWITEMS, 0, 2);
5976 expect(TRUE, ret);
5978 ret = SendMessageA(list, LVM_REDRAWITEMS, 1, 0);
5979 expect(TRUE, ret);
5981 ret = SendMessageA(list, LVM_REDRAWITEMS, 2, 3);
5982 expect(TRUE, ret);
5984 DestroyWindow(list);
5987 static void test_WM_PRINTCLIENT(void)
5989 static const int states[] = {SW_HIDE, SW_SHOW};
5990 static const LPARAM params[] = {0, PRF_CHECKVISIBLE, PRF_NONCLIENT, PRF_CLIENT, PRF_ERASEBKGND,
5991 PRF_CHILDREN, PRF_OWNED};
5992 const DWORD list_background = RGB(255, 0, 0);
5993 const DWORD text_background = RGB(0, 0, 255);
5994 HWND hList;
5995 COLORREF clr;
5996 LONG ret;
5997 RECT rc;
5998 HDC hdc;
5999 int i, j;
6001 hList = create_listview_control(LVS_LIST);
6002 insert_item(hList, 0);
6004 ret = SendMessageA(hList, LVM_SETBKCOLOR, 0, list_background);
6005 ok(ret == TRUE, "got 0x%lx, expected 0x%x\n", ret, TRUE);
6007 ret = SendMessageA(hList, LVM_SETTEXTBKCOLOR, 0, text_background);
6008 ok(ret == TRUE, "got 0x%lx, expected 0x%x\n", ret, TRUE);
6010 hdc = GetDC(hwndparent);
6011 GetClientRect(hwndparent, &rc);
6013 for (i = 0; i < ARRAY_SIZE(states); i++)
6015 ShowWindow(hList, states[i]);
6017 for (j = 0; j < ARRAY_SIZE(params); j++)
6019 winetest_push_context("state=%d lParam=0x%Ix", states[i], params[j]);
6021 FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
6022 clr = GetPixel(hdc, 1, 1);
6023 ok(clr == RGB(0, 0, 0), "got 0x%lx\n", clr);
6024 clr = GetPixel(hdc, 50, 1);
6025 ok(clr == RGB(0, 0, 0), "got 0x%lx\n", clr);
6026 ret = SendMessageA(hList, WM_PRINTCLIENT, (WPARAM)hdc, params[j]);
6027 ok(ret == 0, "got %ld\n", ret);
6028 clr = GetPixel(hdc, 1, 1);
6029 ok(clr == text_background, "got 0x%lx\n", clr);
6030 clr = GetPixel(hdc, 50, 1);
6031 ok(clr == RGB(0, 0, 0), "got 0x%lx\n", clr);
6033 winetest_pop_context();
6037 ReleaseDC(hwndparent, hdc);
6038 DestroyWindow(hList);
6041 static void test_imagelists(void)
6043 HWND hwnd, header;
6044 HIMAGELIST himl1, himl2, himl3;
6045 LRESULT ret;
6047 himl1 = pImageList_Create(40, 40, 0, 4, 4);
6048 himl2 = pImageList_Create(40, 40, 0, 4, 4);
6049 himl3 = pImageList_Create(40, 40, 0, 4, 4);
6050 ok(himl1 != NULL, "Failed to create imagelist\n");
6051 ok(himl2 != NULL, "Failed to create imagelist\n");
6052 ok(himl3 != NULL, "Failed to create imagelist\n");
6054 hwnd = create_listview_control(LVS_REPORT | LVS_SHAREIMAGELISTS);
6055 header = subclass_header(hwnd);
6057 ok(header != NULL, "Expected header\n");
6058 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6059 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6061 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6063 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
6064 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6065 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6066 "set normal image list", FALSE);
6068 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6070 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
6071 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6072 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6073 "set state image list", TRUE);
6075 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6076 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6078 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6080 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
6081 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6082 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_header_set_imagelist,
6083 "set small image list", FALSE);
6085 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6086 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
6087 DestroyWindow(hwnd);
6089 hwnd = create_listview_control(WS_VISIBLE | LVS_ICON);
6091 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6093 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)himl1);
6094 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6095 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6096 "set normal image list", FALSE);
6098 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6100 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM)himl2);
6101 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6102 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6103 "set state image list", FALSE);
6105 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6107 ret = SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl3);
6108 ok(ret == 0, "Expected no imagelist, got %p\n", (HIMAGELIST)ret);
6109 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_set_imagelist,
6110 "set small image list", FALSE);
6112 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6113 ok(header == NULL, "Expected no header, got %p\n", header);
6115 SetWindowLongPtrA(hwnd, GWL_STYLE, GetWindowLongPtrA(hwnd, GWL_STYLE) | LVS_REPORT);
6117 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6118 ok(header != NULL, "Expected header, got NULL\n");
6120 ret = SendMessageA(header, HDM_GETIMAGELIST, 0, 0);
6121 ok((HIMAGELIST)ret == himl3, "Expected imagelist %p, got %p\n", himl3, (HIMAGELIST)ret);
6123 DestroyWindow(hwnd);
6126 static void test_deleteitem(void)
6128 LVITEMA item;
6129 UINT state;
6130 HWND hwnd;
6131 BOOL ret;
6133 hwnd = create_listview_control(LVS_REPORT);
6135 insert_item(hwnd, 0);
6136 insert_item(hwnd, 0);
6137 insert_item(hwnd, 0);
6138 insert_item(hwnd, 0);
6139 insert_item(hwnd, 0);
6141 g_focus_test_LVN_DELETEITEM = TRUE;
6143 /* delete focused item (not the last index) */
6144 item.stateMask = LVIS_FOCUSED;
6145 item.state = LVIS_FOCUSED;
6146 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 2, (LPARAM)&item);
6147 ok(ret == TRUE, "got %d\n", ret);
6148 ret = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
6149 ok(ret == TRUE, "got %d\n", ret);
6150 /* next item gets focus */
6151 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
6152 ok(state == LVIS_FOCUSED, "got %x\n", state);
6154 /* focus last item and delete it */
6155 item.stateMask = LVIS_FOCUSED;
6156 item.state = LVIS_FOCUSED;
6157 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 3, (LPARAM)&item);
6158 ok(ret == TRUE, "got %d\n", ret);
6159 ret = SendMessageA(hwnd, LVM_DELETEITEM, 3, 0);
6160 ok(ret == TRUE, "got %d\n", ret);
6161 /* new last item gets focus */
6162 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 2, LVIS_FOCUSED);
6163 ok(state == LVIS_FOCUSED, "got %x\n", state);
6165 /* focus first item and delete it */
6166 item.stateMask = LVIS_FOCUSED;
6167 item.state = LVIS_FOCUSED;
6168 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6169 ok(ret == TRUE, "got %d\n", ret);
6170 ret = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
6171 ok(ret == TRUE, "got %d\n", ret);
6172 /* new first item gets focus */
6173 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
6174 ok(state == LVIS_FOCUSED, "got %x\n", state);
6176 g_focus_test_LVN_DELETEITEM = FALSE;
6178 DestroyWindow(hwnd);
6181 static const struct message parent_insert_focused0_seq[] = {
6182 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGING },
6183 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGED },
6184 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6185 { 0 }
6188 static const struct message parent_insert_focused1_seq[] = {
6189 { WM_NOTIFY, sent|id|wparam|lparam, 1, LVIF_STATE, LVN_ITEMCHANGING },
6190 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGING },
6191 { WM_NOTIFY, sent|id|wparam|lparam, 0, LVIF_STATE, LVN_ITEMCHANGED },
6192 { WM_NOTIFY, sent|id|wparam|lparam, 1, LVIF_STATE, LVN_ITEMCHANGED },
6193 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6194 { 0 }
6197 static const struct message parent_insert_item_seq[] = {
6198 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6199 { 0 }
6202 static const struct message parent_insert_selected_seq[] = {
6203 { WM_NOTIFY, sent|id|wparam|lparam, 3, LVIF_STATE, LVN_ITEMCHANGING },
6204 { WM_NOTIFY, sent|id|wparam|lparam, 3, LVIF_STATE, LVN_ITEMCHANGED },
6205 { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
6206 { 0 }
6209 #define LVIS_ALL (LVIS_FOCUSED | LVIS_SELECTED | LVIS_CUT | LVIS_DROPHILITED | LVIS_ACTIVATING)
6211 static void test_LVM_INSERTITEM(void)
6213 static const struct
6215 UINT mask, state, stateMask;
6216 } insert_item[] =
6218 { LVIF_STATE, LVIS_FOCUSED, LVIS_FOCUSED },
6219 { LVIF_STATE, LVIS_FOCUSED, 0 },
6220 { LVIF_STATE, 0, LVIS_FOCUSED },
6222 { LVIF_STATE, LVIS_SELECTED, LVIS_SELECTED },
6223 { LVIF_STATE, LVIS_SELECTED, 0 },
6224 { LVIF_STATE, 0, LVIS_SELECTED },
6226 { LVIF_STATE, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED },
6227 { LVIF_STATE, LVIS_FOCUSED | LVIS_SELECTED, 0 },
6228 { LVIF_STATE, 0, LVIS_FOCUSED | LVIS_SELECTED },
6230 { LVIF_STATE, LVIS_FOCUSED, LVIS_ALL },
6231 { LVIF_STATE, LVIS_SELECTED, LVIS_ALL },
6232 { LVIF_STATE, LVIS_CUT, LVIS_ALL },
6233 { LVIF_STATE, LVIS_DROPHILITED, LVIS_ALL },
6234 { LVIF_STATE, LVIS_ACTIVATING, LVIS_ALL },
6236 { LVIF_STATE, LVIS_ALL, LVIS_ALL },
6237 { LVIF_STATE, LVIS_ALL, 0 },
6238 { LVIF_STATE, 0, LVIS_ALL },
6240 { LVIF_STATE | LVIF_PARAM, 0, 0 },
6241 { LVIF_STATE | LVIF_PARAM, LVIS_FOCUSED, LVIS_FOCUSED },
6242 { LVIF_STATE | LVIF_PARAM, LVIS_FOCUSED, 0 },
6243 { LVIF_STATE | LVIF_PARAM, 0, LVIS_FOCUSED },
6245 { LVIF_STATE | LVIF_PARAM, LVIS_SELECTED, LVIS_SELECTED },
6246 { LVIF_STATE | LVIF_PARAM, LVIS_SELECTED, 0 },
6247 { LVIF_STATE | LVIF_PARAM, 0, LVIS_SELECTED },
6249 { LVIF_STATE, 0, 0 },
6250 { LVIF_PARAM, 0, 0 },
6252 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
6253 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, LVIS_FOCUSED },
6254 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, 0 },
6255 { LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_FOCUSED },
6257 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
6258 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, LVIS_FOCUSED },
6259 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_FOCUSED, 0 },
6260 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_FOCUSED },
6262 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, 0 },
6263 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_ALL, LVIS_ALL },
6264 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, LVIS_ALL, 0 },
6265 { LVIF_STATE | LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE, 0, LVIS_ALL },
6267 LVITEMA item;
6268 UINT state;
6269 HWND hwnd;
6270 INT ret, i;
6271 char buf[256];
6273 for (i = 0; i < ARRAYSIZE(insert_item); i++)
6275 hwnd = create_listview_control(LVS_REPORT);
6277 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6279 item.mask = insert_item[i].mask;
6280 item.state = insert_item[i].state;
6281 item.stateMask = insert_item[i].stateMask;
6282 item.pszText = (LPSTR)"Hello World!";
6283 item.iImage = I_IMAGECALLBACK;
6284 item.iItem = 0;
6285 item.iSubItem = 0;
6286 item.lParam = 0xdeadbeef;
6287 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6288 ok(ret == 0, "%d: got %d\n", i, ret);
6290 if ((insert_item[i].mask & LVIF_STATE) && (insert_item[i].state & (LVIS_FOCUSED | LVIS_SELECTED)))
6292 sprintf(buf, "%d: insert focused", i);
6293 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused0_seq, buf, FALSE);
6295 else
6297 sprintf(buf, "%d: insert item", i);
6298 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, buf, FALSE);
6301 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_ALL);
6302 if ((insert_item[i].mask & LVIF_STATE) && insert_item[i].state)
6303 ok(state == insert_item[i].state, "%d: expected %#x, got %#x\n", i, insert_item[i].state, state);
6304 else
6305 ok(state == 0, "%d: expected 0, got %#x\n", i, state);
6307 DestroyWindow(hwnd);
6311 static void test_insertitem(void)
6313 LVITEMA item;
6314 UINT state;
6315 HWND hwnd;
6316 INT ret;
6318 hwnd = create_listview_control(LVS_REPORT);
6320 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6322 /* insert item 0 focused */
6323 item.mask = LVIF_STATE;
6324 item.state = LVIS_FOCUSED;
6325 item.stateMask = LVIS_FOCUSED;
6326 item.iItem = 0;
6327 item.iSubItem = 0;
6328 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6329 ok(ret == 0, "got %d\n", ret);
6330 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused0_seq, "insert focused 0", FALSE);
6332 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 0, LVIS_FOCUSED);
6333 ok(state == LVIS_FOCUSED, "got %x\n", state);
6335 /* insert item 1, focus shift */
6336 item.mask = LVIF_STATE;
6337 item.state = LVIS_FOCUSED;
6338 item.stateMask = LVIS_FOCUSED;
6339 item.iItem = 1;
6340 item.iSubItem = 0;
6341 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6342 ok(ret == 1, "got %d\n", ret);
6343 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_focused1_seq, "insert focused 1", FALSE);
6345 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
6346 ok(state == LVIS_FOCUSED, "got %x\n", state);
6348 /* insert item 2, no focus shift */
6349 item.mask = LVIF_STATE;
6350 item.state = 0;
6351 item.stateMask = LVIS_FOCUSED;
6352 item.iItem = 2;
6353 item.iSubItem = 0;
6354 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6355 ok(ret == 2, "got %d\n", ret);
6356 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert focused 2", FALSE);
6358 state = SendMessageA(hwnd, LVM_GETITEMSTATE, 1, LVIS_FOCUSED);
6359 ok(state == LVIS_FOCUSED, "got %x\n", state);
6361 /* insert item 3 */
6362 item.mask = LVIF_STATE | LVIF_PARAM;
6363 item.state = LVIS_SELECTED;
6364 item.stateMask = LVIS_SELECTED;
6365 item.iItem = 3;
6366 item.iSubItem = 0;
6367 item.lParam = 0xdeadbeef;
6368 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6369 ok(ret == 3, "got %d\n", ret);
6370 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_selected_seq, "insert selected", FALSE);
6372 /* insert item 4 */
6373 item.mask = LVIF_PARAM;
6374 item.state = 0;
6375 item.stateMask = 0;
6376 item.iItem = 4;
6377 item.iSubItem = 0;
6378 item.lParam = 0xdeadbeef;
6379 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6380 ok(ret == 4, "got %d\n", ret);
6381 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert param", FALSE);
6383 /* insert item 5 */
6384 item.mask = LVIF_STATE;
6385 item.state = 0;
6386 item.stateMask = 0;
6387 item.iItem = 5;
6388 item.iSubItem = 0;
6389 item.lParam = 0xdeadbeef;
6390 ret = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6391 ok(ret == 5, "got %d\n", ret);
6392 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_insert_item_seq, "insert state", FALSE);
6394 DestroyWindow(hwnd);
6397 static void test_header_proc(void)
6399 HWND hwnd, header, hdr;
6400 WNDPROC proc1, proc2;
6402 hwnd = create_listview_control(LVS_REPORT);
6404 header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0);
6405 ok(header != NULL, "got %p\n", header);
6407 hdr = CreateWindowExA(0, WC_HEADERA, NULL,
6408 WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
6409 0, 0, 0, 0,
6410 NULL, NULL, NULL, NULL);
6411 ok(hdr != NULL, "got %p\n", hdr);
6413 proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC);
6414 proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC);
6415 ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2);
6417 DestroyWindow(hdr);
6418 DestroyWindow(hwnd);
6421 static void flush_events(void)
6423 MSG msg;
6424 int diff = 200;
6425 int min_timeout = 100;
6426 DWORD time = GetTickCount() + diff;
6428 while (diff > 0)
6430 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
6431 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
6432 diff = time - GetTickCount();
6436 static void test_oneclickactivate(void)
6438 TRACKMOUSEEVENT track;
6439 char item1[] = "item1";
6440 LVITEMA item;
6441 HWND hwnd, fg;
6442 RECT rect;
6443 INT r;
6444 POINT orig_pos;
6446 hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo", WS_VISIBLE|WS_CHILD|LVS_LIST,
6447 10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
6448 ok(hwnd != NULL, "failed to create listview window\n");
6449 r = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_ONECLICKACTIVATE);
6450 ok(r == 0, "should return zero\n");
6452 SetForegroundWindow(hwndparent);
6453 flush_events();
6454 fg = GetForegroundWindow();
6455 if (fg != hwndparent)
6457 skip("Window is not in the foreground. Skipping oneclickactivate tests.\n");
6458 DestroyWindow(hwnd);
6459 return;
6462 item.mask = LVIF_TEXT;
6463 item.iItem = 0;
6464 item.iSubItem = 0;
6465 item.iImage = 0;
6466 item.pszText = item1;
6467 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
6468 ok(r == 0, "should not fail\n");
6470 GetWindowRect(hwnd, &rect);
6471 GetCursorPos(&orig_pos);
6472 SetCursorPos(rect.left+5, rect.top+5);
6473 flush_events();
6474 r = SendMessageA(hwnd, WM_MOUSEMOVE, MAKELONG(1, 1), 0);
6475 expect(0, r);
6477 track.cbSize = sizeof(track);
6478 track.dwFlags = TME_QUERY;
6479 p_TrackMouseEvent(&track);
6480 ok(track.hwndTrack == hwnd, "hwndTrack != hwnd\n");
6481 ok(track.dwFlags == TME_LEAVE, "dwFlags = %lx\n", track.dwFlags);
6483 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
6484 expect(0, r);
6485 r = SendMessageA(hwnd, WM_MOUSEHOVER, MAKELONG(1, 1), 0);
6486 expect(0, r);
6487 r = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
6488 expect(1, r);
6490 DestroyWindow(hwnd);
6491 SetCursorPos(orig_pos.x, orig_pos.y);
6494 static void test_callback_mask(void)
6496 LVITEMA item;
6497 DWORD mask;
6498 HWND hwnd;
6499 BOOL ret;
6501 hwnd = create_listview_control(LVS_REPORT);
6503 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 0);
6504 ok(ret, "got %d\n", ret);
6506 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, ~0u, 1);
6507 ok(ret, "got %d\n", ret);
6509 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6510 ok(mask == ~0u, "got 0x%08lx\n", mask);
6512 /* Ask for state, invalid subitem. */
6513 insert_item(hwnd, 0);
6515 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
6516 ok(ret, "Failed to set callback mask.\n");
6518 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6520 memset(&item, 0, sizeof(item));
6521 item.iSubItem = 1;
6522 item.mask = LVIF_STATE;
6523 item.stateMask = LVIS_SELECTED;
6524 ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6525 ok(ret, "Failed to get item data.\n");
6527 memset(&item, 0, sizeof(item));
6528 item.mask = LVIF_STATE;
6529 item.stateMask = LVIS_SELECTED;
6530 ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6531 ok(ret, "Failed to get item data.\n");
6533 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, callback mask/invalid subitem 1", TRUE);
6535 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6537 memset(&item, 0, sizeof(item));
6538 memset(&g_itema, 0, sizeof(g_itema));
6539 item.iSubItem = 1;
6540 item.mask = LVIF_STATE;
6541 item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
6542 ret = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6543 ok(ret, "Failed to get item data.\n");
6544 ok(g_itema.iSubItem == 1, "Unexpected LVN_DISPINFO subitem %d.\n", g_itema.iSubItem);
6545 ok(g_itema.stateMask == LVIS_FOCUSED, "Unexpected state mask %#x.\n", g_itema.stateMask);
6547 ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
6548 "parent seq, callback mask/invalid subitem 2", FALSE);
6550 DestroyWindow(hwnd);
6552 /* LVS_OWNERDATA, mask LVIS_FOCUSED */
6553 hwnd = create_listview_control(LVS_REPORT | LVS_OWNERDATA);
6555 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6556 ok(mask == 0, "Unexpected callback mask %#lx.\n", mask);
6558 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_FOCUSED, 0);
6559 ok(ret, "Failed to set callback mask, %d\n", ret);
6561 mask = SendMessageA(hwnd, LVM_GETCALLBACKMASK, 0, 0);
6562 ok(mask == LVIS_FOCUSED, "Unexpected callback mask %#lx.\n", mask);
6564 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6565 ok(ret, "Failed to set item count.\n");
6567 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6568 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6570 item.stateMask = LVIS_FOCUSED;
6571 item.state = LVIS_FOCUSED;
6572 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6573 ok(ret, "Failed to set item state.\n");
6575 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6577 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6578 todo_wine
6579 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6581 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6582 todo_wine
6583 ok(ret == 0, "Unexpected selection mark, %d\n", ret);
6585 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
6586 ok(ret, "Failed to set item count.\n");
6588 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6589 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6591 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6592 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6594 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6595 ok(ret, "Failed to set item count.\n");
6597 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6598 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6600 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 1", FALSE);
6602 /* LVS_OWNDERDATA, empty mask */
6603 ret = SendMessageA(hwnd, LVM_SETCALLBACKMASK, 0, 0);
6604 ok(ret, "Failed to set callback mask, %d\n", ret);
6606 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6607 ok(ret, "Failed to set item count.\n");
6609 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6610 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6612 item.stateMask = LVIS_FOCUSED;
6613 item.state = LVIS_FOCUSED;
6614 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6615 ok(ret, "Failed to set item state.\n");
6617 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6618 ok(ret == 0, "Unexpected selection mark, %d\n", ret);
6620 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6622 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6623 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6625 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 0, 0);
6626 ok(ret, "Failed to set item count.\n");
6628 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6629 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6631 ret = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
6632 todo_wine
6633 ok(ret == -1, "Unexpected selection mark, %d\n", ret);
6635 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6636 ok(ret, "Failed to set item count.\n");
6638 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6639 ok(ret == -1, "Unexpected focused item, ret %d\n", ret);
6641 ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "parent seq, owner data/focus 2", FALSE);
6643 /* 2 items, focus on index 0, reduce to 1 item. */
6644 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6646 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 2, 0);
6647 ok(ret, "Failed to set item count.\n");
6649 ret = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6650 ok(ret, "Failed to set item state.\n");
6652 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6653 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6655 ret = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
6656 ok(ret, "Failed to set item count.\n");
6658 ret = SendMessageA(hwnd, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
6659 ok(ret == 0, "Unexpected focused item, ret %d\n", ret);
6661 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_focus_change_ownerdata_seq,
6662 "parent seq, owner data/focus 3", TRUE);
6664 DestroyWindow(hwnd);
6667 static void test_state_image(void)
6669 static const DWORD styles[] =
6671 LVS_ICON,
6672 LVS_REPORT,
6673 LVS_SMALLICON,
6674 LVS_LIST,
6676 int i;
6678 for (i = 0; i < ARRAY_SIZE(styles); i++)
6680 static char text[] = "Item";
6681 static char subtext[] = "Subitem";
6682 char buff[16];
6683 LVITEMA item;
6684 HWND hwnd;
6685 int r;
6687 hwnd = create_listview_control(styles[i]);
6689 insert_column(hwnd, 0);
6690 insert_column(hwnd, 1);
6692 item.mask = LVIF_TEXT | LVIF_PARAM;
6693 item.iItem = 0;
6694 item.iSubItem = 0;
6695 item.pszText = text;
6696 item.lParam = 123456;
6697 r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6698 ok(r == 0, "Failed to insert an item.\n");
6700 item.mask = LVIF_STATE;
6701 item.state = INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED;
6702 item.stateMask = LVIS_STATEIMAGEMASK | LVIS_SELECTED | LVIS_FOCUSED;
6703 item.iItem = 0;
6704 item.iSubItem = 0;
6705 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6706 ok(r, "Failed to set item state.\n");
6708 item.mask = LVIF_TEXT;
6709 item.iItem = 0;
6710 item.iSubItem = 1;
6711 item.pszText = subtext;
6712 r = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6713 ok(r, "Failed to set subitem text.\n");
6715 item.mask = LVIF_STATE | LVIF_PARAM;
6716 item.stateMask = ~0u;
6717 item.state = 0;
6718 item.iItem = 0;
6719 item.iSubItem = 0;
6720 item.lParam = 0;
6721 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6722 ok(r, "Failed to get item state.\n");
6723 ok(item.state == (INDEXTOSTATEIMAGEMASK(1) | LVIS_SELECTED | LVIS_FOCUSED),
6724 "Unexpected item state %#x.\n", item.state);
6725 ok(item.lParam == 123456, "Unexpected lParam %Id.\n", item.lParam);
6727 item.mask = 0;
6728 item.stateMask = ~0u;
6729 item.state = INDEXTOSTATEIMAGEMASK(2);
6730 item.iItem = 0;
6731 item.iSubItem = 1;
6732 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6733 ok(r, "Failed to get subitem state.\n");
6734 ok(item.state == INDEXTOSTATEIMAGEMASK(2), "Unexpected state %#x.\n", item.state);
6736 item.mask = LVIF_STATE | LVIF_PARAM;
6737 item.stateMask = ~0u;
6738 item.state = INDEXTOSTATEIMAGEMASK(2);
6739 item.iItem = 0;
6740 item.iSubItem = 1;
6741 item.lParam = 0;
6742 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6743 ok(r, "Failed to get subitem state.\n");
6744 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6745 ok(item.lParam == 123456, "Unexpected lParam %Id.\n", item.lParam);
6747 item.mask = LVIF_STATE;
6748 item.stateMask = LVIS_FOCUSED;
6749 item.state = 0;
6750 item.iItem = 0;
6751 item.iSubItem = 1;
6752 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6753 ok(r, "Failed to get subitem state.\n");
6754 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6756 item.mask = LVIF_STATE;
6757 item.stateMask = ~0u;
6758 item.state = INDEXTOSTATEIMAGEMASK(2);
6759 item.iItem = 0;
6760 item.iSubItem = 2;
6761 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6762 ok(r, "Failed to get subitem state.\n");
6763 ok(item.state == 0, "Unexpected state %#x.\n", item.state);
6765 item.mask = LVIF_TEXT;
6766 item.iItem = 0;
6767 item.iSubItem = 1;
6768 item.pszText = buff;
6769 item.cchTextMax = sizeof(buff);
6770 r = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
6771 ok(r, "Failed to get subitem text %d.\n", r);
6772 ok(!strcmp(buff, subtext), "Unexpected subitem text %s.\n", buff);
6774 DestroyWindow(hwnd);
6778 static void test_LVSCW_AUTOSIZE(void)
6780 int width, width2;
6781 HWND hwnd;
6782 BOOL ret;
6784 hwnd = create_listview_control(LVS_REPORT);
6785 ok(hwnd != NULL, "failed to create a listview window\n");
6787 insert_column(hwnd, 0);
6788 insert_column(hwnd, 1);
6789 insert_item(hwnd, 0);
6791 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6792 ok(ret, "Failed to set column width.\n");
6794 width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6795 ok(width > 0, "Unexpected column width %d.\n", width);
6797 /* Turn on checkboxes. */
6798 ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
6799 ok(ret == 0, "Unexpected previous extended style.\n");
6801 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6802 ok(ret, "Failed to set column width.\n");
6804 width2 = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6805 ok(width2 > 0, "Unexpected column width %d.\n", width2);
6806 ok(width2 > width, "Expected increased column width.\n");
6808 /* Turn off checkboxes. */
6809 ret = SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
6810 ok(ret == LVS_EX_CHECKBOXES, "Unexpected previous extended style.\n");
6812 ret = SendMessageA(hwnd, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE);
6813 ok(ret, "Failed to set column width.\n");
6815 width = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
6816 ok(width > 0, "Unexpected column width %d.\n", width2);
6817 ok(width2 > width, "Expected reduced column width.\n");
6819 DestroyWindow(hwnd);
6822 static void test_LVN_ENDLABELEDIT(void)
6824 WCHAR text[] = {'l','a','l','a',0};
6825 HWND hwnd, hwndedit;
6826 LVITEMW item = {0};
6827 DWORD ret;
6829 hwnd = create_listview_control(LVS_REPORT | LVS_EDITLABELS);
6831 insert_column(hwnd, 0);
6833 item.mask = LVIF_TEXT;
6834 item.pszText = text;
6835 SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
6837 /* Test normal editing */
6838 SetFocus(hwnd);
6839 hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
6840 ok(hwndedit != NULL, "Failed to get edit control.\n");
6842 ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test");
6843 ok(ret, "Failed to set edit text.\n");
6845 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6847 ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
6848 ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit, "Label edit", FALSE);
6850 /* Test editing with kill focus */
6851 SetFocus(hwnd);
6852 hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
6853 ok(hwndedit != NULL, "Failed to get edit control.\n");
6855 ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test2");
6856 ok(ret, "Failed to set edit text.\n");
6858 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6860 g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = TRUE;
6861 ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
6862 g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = FALSE;
6864 ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit_kill_focus,
6865 "Label edit, kill focus", FALSE);
6866 ok(GetFocus() == hwnd, "Unexpected focused window.\n");
6868 flush_sequences(sequences, NUM_MSG_SEQUENCES);
6870 DestroyWindow(hwnd);
6873 static LRESULT CALLBACK create_item_height_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
6875 if (msg == WM_CREATE)
6876 return 0;
6878 return CallWindowProcA(listviewWndProc, hwnd, msg, wParam, lParam);
6881 static void test_LVM_GETCOUNTPERPAGE(void)
6883 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
6884 unsigned int i, j;
6885 WNDCLASSEXA cls;
6886 ATOM class;
6887 HWND hwnd;
6888 BOOL ret;
6890 cls.cbSize = sizeof(WNDCLASSEXA);
6891 ret = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
6892 ok(ret, "Failed to get class info.\n");
6893 listviewWndProc = cls.lpfnWndProc;
6894 cls.lpfnWndProc = create_item_height_wndproc;
6895 cls.lpszClassName = "CountPerPageClass";
6896 class = RegisterClassExA(&cls);
6897 ok(class, "Failed to register class.\n");
6899 for (i = 0; i < ARRAY_SIZE(styles); i++)
6901 static char text[] = "item text";
6902 LVITEMA item = { 0 };
6903 UINT count, count2;
6905 hwnd = create_listview_control(styles[i]);
6906 ok(hwnd != NULL, "Failed to create listview window.\n");
6908 count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6909 if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
6910 ok(count > 0 || broken(styles[i] == LVS_LIST && count == 0), "%u: unexpected count %u.\n", i, count);
6911 else
6912 ok(count == 0, "%u: unexpected count %u.\n", i, count);
6914 for (j = 0; j < 10; j++)
6916 item.mask = LVIF_TEXT;
6917 item.pszText = text;
6918 SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
6921 count2 = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6922 if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
6923 ok(count == count2, "%u: unexpected count %u.\n", i, count2);
6924 else
6925 ok(count2 == 10, "%u: unexpected count %u.\n", i, count2);
6927 DestroyWindow(hwnd);
6929 hwnd = CreateWindowA("CountPerPageClass", "Test", WS_VISIBLE | styles[i], 0, 0, 100, 100, NULL, NULL,
6930 GetModuleHandleA(NULL), 0);
6931 ok(hwnd != NULL, "Failed to create a window.\n");
6933 count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
6934 ok(count == 0, "%u: unexpected count %u.\n", i, count);
6936 DestroyWindow(hwnd);
6939 ret = UnregisterClassA("CountPerPageClass", NULL);
6940 ok(ret, "Failed to unregister test class.\n");
6943 static void test_item_state_change(void)
6945 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
6946 LVITEMA item;
6947 HWND hwnd;
6948 DWORD res;
6949 int i;
6951 for (i = 0; i < ARRAY_SIZE(styles); i++)
6953 hwnd = create_listview_control(styles[i]);
6955 insert_item(hwnd, 0);
6957 /* LVM_SETITEMSTATE with mask */
6958 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6959 memset(&item, 0, sizeof(item));
6960 item.mask = LVIF_STATE;
6961 item.stateMask = LVIS_SELECTED;
6962 item.state = LVIS_SELECTED;
6963 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6964 ok(res, "Failed to set item state.\n");
6966 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6967 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6968 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
6969 ok(g_nmlistview.uNewState == LVIS_SELECTED, "got new state 0x%08x\n", g_nmlistview.uNewState);
6970 ok(g_nmlistview.uOldState == 0, "got old state 0x%08x\n", g_nmlistview.uOldState);
6971 ok(g_nmlistview.uChanged == LVIF_STATE, "got changed 0x%08x\n", g_nmlistview.uChanged);
6973 /* LVM_SETITEMSTATE 0 mask */
6974 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6975 memset(&item, 0, sizeof(item));
6976 item.stateMask = LVIS_SELECTED;
6977 item.state = 0;
6978 res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
6979 ok(res, "Failed to set item state.\n");
6981 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6982 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6983 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
6984 ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
6985 ok(g_nmlistview.uOldState == LVIS_SELECTED, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
6986 ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
6988 /* LVM_SETITEM changes state */
6989 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
6990 memset(&item, 0, sizeof(item));
6991 item.stateMask = LVIS_SELECTED;
6992 item.state = LVIS_SELECTED;
6993 item.mask = LVIF_STATE;
6994 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
6995 ok(res, "Failed to set item.\n");
6997 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
6998 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
6999 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
7000 ok(g_nmlistview.uNewState == LVIS_SELECTED, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
7001 ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
7002 ok(g_nmlistview.uChanged == LVIF_STATE, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
7004 /* LVM_SETITEM no state changes */
7005 memset(&g_nmlistview, 0xcc, sizeof(g_nmlistview));
7006 memset(&item, 0, sizeof(item));
7007 item.lParam = 11;
7008 item.mask = LVIF_PARAM;
7009 res = SendMessageA(hwnd, LVM_SETITEMA, 0, (LPARAM)&item);
7010 ok(res, "Failed to set item.\n");
7012 ok(g_nmlistview.iItem == item.iItem, "Unexpected item %d.\n", g_nmlistview.iItem);
7013 ok(g_nmlistview.iSubItem == item.iSubItem, "Unexpected subitem %d.\n", g_nmlistview.iSubItem);
7014 ok(g_nmlistview.lParam == item.lParam, "Unexpected lParam.\n");
7015 ok(g_nmlistview.uNewState == 0, "Unexpected new state %#x.\n", g_nmlistview.uNewState);
7016 ok(g_nmlistview.uOldState == 0, "Unexpected old state %#x.\n", g_nmlistview.uOldState);
7017 ok(g_nmlistview.uChanged == LVIF_PARAM, "Unexpected change mask %#x.\n", g_nmlistview.uChanged);
7019 DestroyWindow(hwnd);
7023 static void test_selected_column(void)
7025 static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
7026 int ret, i;
7027 HWND hwnd;
7029 for (i = 0; i < ARRAY_SIZE(styles); ++i)
7031 hwnd = create_listview_control(styles[i]);
7033 /* Initial value */
7034 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
7035 ok(ret == -1, "Unexpected column %d.\n", ret);
7037 ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, -100, 0);
7038 ok(ret == 1, "Unexpected return value %d.\n", ret);
7040 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
7041 ok(ret == -100, "Unexpected column %d.\n", ret);
7043 ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, 100, 0);
7044 ok(ret == 1, "Unexpected return value %d.\n", ret);
7046 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
7047 ok(ret == 100, "Unexpected column %d.\n", ret);
7049 ret = SendMessageA(hwnd, LVM_SETSELECTEDCOLUMN, -1, 0);
7050 ok(ret == 1, "Unexpected return value %d.\n", ret);
7052 ret = SendMessageA(hwnd, LVM_GETSELECTEDCOLUMN, 0, 0);
7053 ok(ret == -1, "Unexpected column %d.\n", ret);
7055 DestroyWindow(hwnd);
7059 static void test_LVM_GETNEXTITEMINDEX(void)
7061 LVITEMINDEX index;
7062 HWND hwnd;
7063 BOOL ret;
7065 hwnd = create_listview_control(LVS_REPORT);
7067 insert_item(hwnd, 0);
7068 insert_item(hwnd, 1);
7070 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, 0, LVNI_ALL);
7071 ok(!ret, "Unexpected return value %d.\n", ret);
7073 index.iItem = -1;
7074 index.iGroup = 0;
7075 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
7076 ok(ret, "Unexpected return value %d.\n", ret);
7077 ok(index.iItem == 0, "Unexpected item index %d.\n", index.iItem);
7079 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
7080 ok(ret, "Unexpected return value %d.\n", ret);
7081 ok(index.iItem == 1, "Unexpected item index %d.\n", index.iItem);
7083 ret = SendMessageA(hwnd, LVM_GETNEXTITEMINDEX, (WPARAM)&index, LVNI_ALL);
7084 ok(!ret, "Unexpected return value %d.\n", ret);
7085 ok(index.iItem == -1, "Unexpected item index %d.\n", index.iItem);
7087 DestroyWindow(hwnd);
7090 static void test_LVM_SETBKIMAGE(BOOL is_v6)
7092 LVBKIMAGEA image;
7093 HBITMAP hbmp;
7094 BITMAP bm;
7095 HWND hwnd;
7096 int ret;
7098 CoInitialize(NULL);
7100 hbmp = CreateBitmap(32, 32, 1, 1, NULL);
7101 hwnd = create_listview_control(LVS_REPORT);
7103 image.ulFlags = LVBKIF_SOURCE_NONE;
7104 image.hbm = 0;
7105 image.pszImage = NULL;
7106 image.cchImageMax = 0;
7107 image.xOffsetPercent = 0;
7108 image.yOffsetPercent = 0;
7109 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7110 ok(!ret, "got %d\n", ret);
7112 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7113 ok(ret == sizeof(bm), "got %d\n", ret);
7115 image.ulFlags = LVBKIF_SOURCE_HBITMAP;
7116 image.hbm = hbmp;
7117 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7118 if (is_v6)
7119 ok(ret, "got %d\n", ret);
7120 else
7121 todo_wine ok(!ret, "got %d\n", ret);
7123 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7124 ok(ret == sizeof(bm), "got %d\n", ret);
7126 image.ulFlags = LVBKIF_SOURCE_NONE;
7127 image.hbm = 0;
7128 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7129 ok(!ret, "got %d\n", ret);
7131 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7132 ok(!ret, "got %d\n", ret);
7134 hbmp = CreateBitmap(32, 32, 1, 1, NULL);
7136 image.ulFlags = LVBKIF_SOURCE_HBITMAP;
7137 image.hbm = hbmp;
7138 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7139 if (is_v6)
7140 ok(ret, "got %d\n", ret);
7141 else
7142 todo_wine ok(!ret, "got %d\n", ret);
7144 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7145 ok(ret == sizeof(bm), "got %d\n", ret);
7147 image.ulFlags = LVBKIF_SOURCE_HBITMAP;
7148 image.hbm = hbmp;
7149 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7150 ok(!ret, "got %d\n", ret);
7152 ret = GetObjectA(hbmp, sizeof(bm), &bm);
7153 ok(!ret, "got %d\n", ret);
7155 image.ulFlags = LVBKIF_SOURCE_NONE;
7156 image.hbm = 0;
7157 ret = SendMessageA(hwnd, LVM_SETBKIMAGEA, 0, (LPARAM)&image);
7158 ok(!ret, "got %d\n", ret);
7160 DestroyWindow(hwnd);
7162 CoUninitialize();
7165 START_TEST(listview)
7167 ULONG_PTR ctx_cookie;
7168 HANDLE hCtx;
7170 init_functions();
7172 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
7174 hwndparent = create_parent_window(FALSE);
7175 flush_sequences(sequences, NUM_MSG_SEQUENCES);
7177 test_header_notification();
7178 test_header_notification2();
7179 test_images();
7180 test_checkboxes();
7181 test_items();
7182 test_create(FALSE);
7183 test_redraw();
7184 test_customdraw();
7185 test_icon_spacing();
7186 test_color();
7187 test_item_count();
7188 test_item_position();
7189 test_columns();
7190 test_getorigin();
7191 test_multiselect();
7192 test_getitemrect();
7193 test_subitem_rect();
7194 test_sorting();
7195 test_ownerdata();
7196 test_ownerdata_multiselect();
7197 test_norecompute();
7198 test_nosortheader();
7199 test_setredraw();
7200 test_hittest();
7201 test_getviewrect();
7202 test_getitemposition();
7203 test_editbox();
7204 test_notifyformat();
7205 test_indentation();
7206 test_getitemspacing();
7207 test_getcolumnwidth();
7208 test_approximate_viewrect();
7209 test_finditem();
7210 test_hover();
7211 test_destroynotify();
7212 test_createdragimage();
7213 test_dispinfo();
7214 test_LVM_SETITEMTEXT();
7215 test_LVM_REDRAWITEMS();
7216 test_WM_PRINTCLIENT();
7217 test_imagelists();
7218 test_deleteitem();
7219 test_insertitem();
7220 test_LVM_INSERTITEM();
7221 test_header_proc();
7222 test_oneclickactivate();
7223 test_callback_mask();
7224 test_state_image();
7225 test_LVSCW_AUTOSIZE();
7226 test_LVN_ENDLABELEDIT();
7227 test_LVM_GETCOUNTPERPAGE();
7228 test_item_state_change();
7229 test_LVM_SETBKIMAGE(FALSE);
7231 if (!load_v6_module(&ctx_cookie, &hCtx))
7233 DestroyWindow(hwndparent);
7234 return;
7237 init_functions();
7239 /* comctl32 version 6 tests start here */
7240 test_get_set_view();
7241 test_canceleditlabel();
7242 test_mapidindex();
7243 test_scrollnotify();
7244 test_LVS_EX_TRANSPARENTBKGND();
7245 test_LVS_EX_HEADERINALLVIEWS();
7246 test_deleteitem();
7247 test_multiselect();
7248 test_insertitem();
7249 test_header_proc();
7250 test_images();
7251 test_checkboxes();
7252 test_items();
7253 test_create(TRUE);
7254 test_color();
7255 test_columns();
7256 test_sorting();
7257 test_ownerdata();
7258 test_ownerdata_multiselect();
7259 test_norecompute();
7260 test_nosortheader();
7261 test_indentation();
7262 test_finditem();
7263 test_hover();
7264 test_destroynotify();
7265 test_createdragimage();
7266 test_dispinfo();
7267 test_LVM_SETITEMTEXT();
7268 test_LVM_REDRAWITEMS();
7269 test_WM_PRINTCLIENT();
7270 test_oneclickactivate();
7271 test_state_image();
7272 test_LVSCW_AUTOSIZE();
7273 test_LVN_ENDLABELEDIT();
7274 test_LVM_GETCOUNTPERPAGE();
7275 test_item_state_change();
7276 test_selected_column();
7277 test_LVM_GETNEXTITEMINDEX();
7278 test_LVM_SETBKIMAGE(TRUE);
7280 unload_v6_module(ctx_cookie, hCtx);
7282 DestroyWindow(hwndparent);